In my C++ application, I am seeing a pclose() that hangs because the pipe's process hung and never exited. Is there anyway I could do something like select() to test whether the pclose() will return because the child process has completed? I'd rather not do a fork() instead of popen() if possible. If fork() is the only solution, are there any examples of using fork() to replace a popen() / pclose() scenario?
Probably the easiest way, particularly if you only have one child process, is to catch SIGCHLD and set a flag that the process has terminated and pclose() can be called.
Here's a simple example:
sillyprog.c:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("This is some data from the child.\n");
fflush(stdout);
sleep(5);
return 0;
}
pc.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
volatile sig_atomic_t child_done = 0;
void handler(int signum)
{
if ( signum == SIGCHLD ) {
child_done = 1;
}
}
int main(void)
{
/* Set signal handler */
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if ( sigaction(SIGCHLD, &sa, NULL) == -1 ) {
perror("couldn't set signal handler");
return EXIT_FAILURE;
}
/* Open pipe */
FILE * fp = popen("./sillyprog", "r");
if ( !fp ) {
fprintf(stderr, "Couldn't open pipe\n");
return EXIT_FAILURE;
}
/* Get a line from pipe */
char buffer[100];
if ( !fgets(buffer, 100, fp) ) {
fprintf(stderr, "Error calling fgets()\n");
return EXIT_FAILURE;
}
const size_t len = strlen(buffer);
if ( len && buffer[len - 1] == '\n' ) {
buffer[len - 1] = 0;
}
printf("Got '%s' from pipe.\n", buffer);
/* Wait for child to finish */
while ( !child_done ) {
printf("Child not ready, waiting...\n");
sleep(1);
}
/* Close pipe */
if ( pclose(fp) == -1 ) {
fprintf(stderr, "Error calling pclose()\n");
return EXIT_FAILURE;
}
else {
printf("pclose() successfully called.\n");
}
return 0;
}
which outputs:
paul#horus:~/src/sandbox$ ./pc
Got 'This is some data from the child.' from pipe.
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
Child not ready, waiting...
pclose() successfully called.
paul#horus:~/src/sandbox$
Related
I am watching the processes with htop and I see that child process stays as zombie even though I clean up with waitpid call. Any idea why this might happen?
Thank you very much!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void child_signal_handler(int signal) {
printf("Someone is stabbed me with signal %d\n", signal);
}
int main(int argc, char** argv)
{
const pid_t child = fork();
if (child == 0) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &child_signal_handler;
sigaction(SIGTERM, &sa, NULL);
printf("Child is started in busy loop\n");
while (true)
;
} else {
const int mercy_period = 3;
printf("Parent is angry and gonna kill his child in %d sec\n", mercy_period);
sleep(mercy_period);
kill(child, SIGTERM);
// clean-up zombie child process as it is terminated before we can wait on
// it
int status = 0;
while(waitpid(-1, &status, WNOHANG) > 0);
}
return EXIT_SUCCESS;
}
waitpid glibc implementation comments
If PID is (pid_t) -1, match any process. If the WNOHANG bit is set in OPTIONS, and that child
is not already dead, return (pid_t) 0.
The while loop clearly exits immediately as 0 > 0 is false.
Change the else and the signal to SIGKILL
} else {
const int mercy_period = 3;
printf("Parent is angry and gonna kill his child in %d sec\n", mercy_period);
sleep(mercy_period);
kill(child, SIGKILL);
int status = 0;
pid_t pid = waitpid(-1, &status, WNOHANG);
while(!pid) {
pid = waitpid(-1, &status, WNOHANG);
printf("%d\n", pid);
}
}
After few attempts waitpid will return the pid of the child process. A success.
I have a program that uses popen() in order to open and read the output from a shell command. The problem is, as far as I can tell, there is no easy way to get the PID of the running process, and hence, you can't kill it if it gets stuck. So the question is, how can you retrieve the PID from a process opened with popen?
The solution I came up with (and the general consensus) is to create a new popen function that allows me to retrieve the PID. Since I was unable to find a simple example of this on SO, I wanted to post my implementation in the hopes that it helps somebody else. Feedback and alternate solutions are welcome.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <string>
#include <sstream>
using namespace std;
#define READ 0
#define WRITE 1
FILE * popen2(string command, string type, int & pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == "r")
{
close(fd[READ]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[WRITE], 1); //Redirect stdout to pipe
}
else
{
close(fd[WRITE]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[READ], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
exit(0);
}
else
{
if (type == "r")
{
close(fd[WRITE]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[READ]); //Close the READ end of the pipe since parent's fd is write-only
}
}
pid = child_pid;
if (type == "r")
{
return fdopen(fd[READ], "r");
}
return fdopen(fd[WRITE], "w");
}
int pclose2(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
int main()
{
int pid;
string command = "ping 8.8.8.8";
FILE * fp = popen2(command, "r", pid);
char command_out[100] = {0};
stringstream output;
//Using read() so that I have the option of using select() if I want non-blocking flow
while (read(fileno(fp), command_out, sizeof(command_out)-1) != 0)
{
output << string(command_out);
kill(-pid, 9);
memset(&command_out, 0, sizeof(command_out));
}
string token;
while (getline(output, token, '\n'))
printf("OUT: %s\n", token.c_str());
pclose2(fp, pid);
return 0;
}
CLARIFICATION
I tried to use the defined functions by #Gillespie's answer but found out that the pid in the C/C++ program was different from the one returned by the terminal command pgrep and looking at the output of ps -aux | grep myNameProc it seemed the process of the C program was forked once more.
I think because execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL); is actually equivalent to /bin/sh cmd string. So basically the child process of your C (or C++) program is creating a new process that does /bin/sh yourRealProcess where yourRealProcess is the one specified in the command string.
I solved doing the following: execl(command.c_str(), command.c_str(), (char*)NULL);. However, as specified by #Gillespie in the previous comments, in this way you will not be able to pass arguments to your process.
C IMPLEMENTATION
According to my needs I readapted #Gillespie's functions to include the above discussed modification and to work in the C programming language:
FILE * custom_popen(char* command, char type, pid_t* pid)
{
pid_t child_pid;
int fd[2];
pipe(fd);
if((child_pid = fork()) == -1)
{
perror("fork");
exit(1);
}
/* child process */
if (child_pid == 0)
{
if (type == 'r')
{
close(fd[0]); //Close the READ end of the pipe since the child's fd is write-only
dup2(fd[1], 1); //Redirect stdout to pipe
}
else
{
close(fd[1]); //Close the WRITE end of the pipe since the child's fd is read-only
dup2(fd[0], 0); //Redirect stdin to pipe
}
setpgid(child_pid, child_pid); //Needed so negative PIDs can kill children of /bin/sh
execl(command, command, (char*)NULL);
exit(0);
}
else
{
printf("child pid %d\n", child_pid);
if (type == 'r')
{
close(fd[1]); //Close the WRITE end of the pipe since parent's fd is read-only
}
else
{
close(fd[0]); //Close the READ end of the pipe since parent's fd is write-only
}
}
*pid = child_pid;
if (type == 'r')
{
return fdopen(fd[0], "r");
}
return fdopen(fd[1], "w");
}
int custom_pclose(FILE * fp, pid_t pid)
{
int stat;
fclose(fp);
while (waitpid(pid, &stat, 0) == -1)
{
if (errno != EINTR)
{
stat = -1;
break;
}
}
return stat;
}
I'm writing daemon with ability to recover work process CentOS release 5.7 (Final).
Here is example of code:
#define CHILD_NEED_WORK 1
#define CHILD_NEED_TERMINATE 2
int ReloadConfig()
{
....
return 0;
}
void DestroyWorkThread()
{...}
int InitWorkThread()
{
...
return 0;
}
int LoadConfig(char* FileName)
{
...
return 0;
}
void SetPidFile(char* Filename)
{
FILE* f;
f = fopen(Filename, "w+");
if (f)
{
fprintf(f, "%u\n", getpid());
fclose(f);
}
}
int SetFdLimit(int MaxFd)
{
struct rlimit lim;
int status;
lim.rlim_cur = MaxFd;
lim.rlim_max = MaxFd;
status = setrlimit(RLIMIT_NOFILE, &lim);
return status;
}
//Monitor process
int MonitorProc()
{
int pid;
int status;
int need_start = 1;
sigset_t sigset;
siginfo_t siginfo;
parent_pid = getpid();
sigemptyset(&sigset);
sigaddset(&sigset, SIGQUIT);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
sigaddset(&sigset, SIGCHLD);
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, NULL);
SetPidFile(PID_FILE);
for (;;)
{
if (need_start)
{
pid = fork();
}
need_start = 1;
if (pid == -1)
{
}
else if (!pid)
{
status = WorkProc();
exit(status);
}
else
{
sigwaitinfo(&sigset, &siginfo);
if (siginfo.si_signo == SIGCHLD)
{
wait(&status);
status = WEXITSTATUS(status);
if (status == CHILD_NEED_TERMINATE)
{
Write("[MONITOR] Child stopped");
break;
}
else if (status == CHILD_NEED_WORK)
{
Write("[MONITOR] Child restart");
}
}
else if (siginfo.si_signo == SIGUSR1)
{
kill(pid, SIGUSR1);
need_start = 0;
}
else if (siginfo.si_signo == 0)
{
need_start = 0;
continue;
}
else
{
Write("[MONITOR] Signal ", strsignal(siginfo.si_signo));
kill(pid, SIGTERM);
status = 0;
break;
}
}
}
Write("[MONITOR] Stop");
unlink(PID_FILE);
return status;
}
//Work process
int WorkProc()
{
struct sigaction sigact;
sigset_t sigset;
int signo;
int status;
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = signal_error_for_backtrace;
sigemptyset(&sigact.sa_mask);
sigaction(SIGFPE, &sigact, 0);
sigaction(SIGILL, &sigact, 0);
sigaction(SIGSEGV, &sigact, 0);
sigaction(SIGBUS, &sigact, 0);
sigemptyset(&sigset);
sigaddset(&sigset, SIGQUIT);
sigaddset(&sigset, SIGINT);
sigaddset(&sigset, SIGTERM);
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_BLOCK, &sigset, NULL);
SetFdLimit(FD_LIMIT);
status = InitWorkThread();
if (!status)
{
for (;;)
{
sigwait(&sigset, &signo);
if (signo == SIGUSR1)
{
status = ReloadConfig();
if (status)
{
Write("[DAEMON] Reload config failed");
}
else
{
Write("[DAEMON] Reload config OK");
}
}
else
{
break;
}
}
DestroyWorkThread();
}
else
{
Write("[DAEMON] Create work thread failed");
}
Write("[DAEMON] Stopped");
return CHILD_NEED_TERMINATE;
}
int main(int argc , char *argv[])
{
if (argc != 2)
{
printf("Usage: ./test_daemon.conf failed!\n");
return -1;
}
status = LoadConfig(argv[1]);
if (status)
{
printf("Error: Load config failed\n");
return -1;
}
if (CheckForAnotherInstance())
{
printf("Daemon is already running!\n");
return 1;
}
pid = fork();
if (pid == -1)
{
printf("Error: Start Daemon failed (%s)\n", strerror(errno));
return -1;
}
else if (!pid)
{
umask(0);
setsid();
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
//Monitor process startup
status = MonitorProc();
return status;
}
else
{
return 0;
}
return 0;
}
I use two processes: work process, which produces main work and monitor process, which waits for signals from work process, and restarts them, if it receives required signal. When i try to send a signal to parent process - monitor process - with command kill -s SIGCHLD, it receives this signal.
When i try to terminate child process, parent process doesn't receive SIGCHLD signal- it contunies to wait for signals, and child process transforms to zombie.
But when i use utility strace with parent process, all works fine - child process terminates successfully, and parent process receives SIGCHLD signal.
I read about function waitpid(), which uses to receive SIGCHLD signal, but i want to receive another signals in parent process too.
Any ideas?
My guess , signal handler is not installed before first fork?
You SIG_BLOCK the SIGCHLD so will no receive any signals. But this is ok as you go on to use sigwaitinfo() but you fail to use siginfo.si_pid when you do a wait(), you should use waitpid() for the PID you are cleaning up due to receiving the signal synchronously via sigwaitinfo().
You use WEXITSTATUS() without checking WIFEXITED(status) first. See wait() man page.
Your monitor and work process appear to use the same executable as you do a fork() with out exec() after. So be careful as you may been to restore the signal handler state in the child to get the code in the child to behave normally.
For example the monitor process is the parent? So to get a child it does a fork() and then calls into WorkProc(). Inside WorkProc() it proceeds to block a bunch of signals (but not SIGCLD). However the execution is the sigprocmask(SIG_BLOCK, ...) from MonitorProc() will still be active inside WorkProc().
I am not sure what "if (siginfo.si_signo == 0) " is all about.
So to another your main query the reason why SIGCHLD is not being delivered from the process running WorkProc() function, is because you blocked that signal already inside MonitorProc(). So fix this issue use the 3rd argument to sigprocmask() to save the original block/unblock mask in MonitorProc() and when you fork() and before jumping into WorkProc() restore the block/unblock mask.
I am trying to implement the timer in code, All the example that I found are using while(1) or for(;;) but when I tried with using scanf my program terminates. Is it getting any value on stdin because if I use scanf two times then timer is called two time before exiting from program.
Here is my sample code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <signal.h>
#include <time.h>
#include <linux/socket.h>
#include <time.h>
#define SIGTIMER (SIGRTMAX)
#define SIG SIGUSR1
static timer_t tid;
static timer_t tid2;
void SignalHandler(int, siginfo_t*, void* );
timer_t SetTimer(int, int);
int main(int argc, char *argv[]) {
int t;
printf("SIGRTMAX %d\n", SIGRTMAX);
printf("SIGRTMIN %d\n", SIGRTMIN);
struct sigaction sigact;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigact.sa_sigaction = SignalHandler;
// set up sigaction to catch signal
if (sigaction(SIGTIMER, &sigact, NULL) == -1) {
perror("sigaction failed");
exit( EXIT_FAILURE );
}
// Establish a handler to catch CTRL+c and use it for exiting.
sigaction(SIGINT, &sigact, NULL);
tid=SetTimer(SIGTIMER, 1000);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SignalHandler;
// set up sigaction to catch signal
if (sigaction(SIG, &sa, NULL) == -1) {
perror("sa failed");
exit( EXIT_FAILURE );
}
// Establish a handler to catch CTRL+c and use it for exiting.
sigaction(SIGINT, &sa, NULL);
tid2=SetTimer(SIG, 1000);
// for(;;); or while(1) Working properly
scanf("%d", &t); /// Program terminates
return 0;
}
void SignalHandler(int signo, siginfo_t* info, void* context)
{
if (signo == SIGTIMER) {
printf("Command Caller has ticked\n");
}else if (signo == SIG) {
printf("Data Caller has ticked\n");
} else if (signo == SIGINT) {
timer_delete(tid);
perror("Crtl+c cached!");
exit(1); // exit if CRTL/C is issued
}
}
timer_t SetTimer(int signo, int sec)
{
static struct sigevent sigev;
static timer_t tid;
static struct itimerspec itval;
static struct itimerspec oitval;
// Create the POSIX timer to generate signo
sigev.sigev_notify = SIGEV_SIGNAL;
sigev.sigev_signo = signo;
sigev.sigev_value.sival_ptr = &tid;
if (timer_create(CLOCK_REALTIME, &sigev, &tid) == 0)
{
itval.it_value.tv_sec = sec / 1000;
itval.it_value.tv_nsec = (long)(sec % 1000) * (1000000L);
itval.it_interval.tv_sec = itval.it_value.tv_sec;
itval.it_interval.tv_nsec = itval.it_value.tv_nsec;
if (timer_settime(tid, 0, &itval, &oitval) != 0)
{
perror("time_settime error!");
}
}
else
{
perror("timer_create error!");
return NULL;
}
return tid;
}
So, How can I resolve this problem ?
Any help would be Appreciated.
Thanks, Yuvi
Signal interrupts scanf. If you add perror('scanf') after scanf output will be:
SIGRTMAX 64
SIGRTMIN 34
Command Caller has ticked
Data Caller has ticked
scanf: Interrupted system call
If you replace scanf with:
do {
errno = 0;
scanf("%d", &t);
} while(errno == EINTR);
scanf will be retried when it fail with Interrupted system call.
You absolutely cannot use printf and perror in a signal handler. They are not re-entrant.
Also, it's possible that scanf will return with an error if your program receives a signal while in it. If scanf returns EOF, check errno, it will probably be EINTR.
I wrote a code in C/C++ which forks a child process, duplicates the stdin/stdout into a pipe ends and calls execvp.
Everything is working fine (i.e. the output from stdin/err/out is captured by the parent process)
The problem is that the child stdout is buffered.
so if the child code looks like this:
printf("Enter any key and hit ENTER:\n");
fgets(line);
printf("read: %s\n", line);
exit(0);
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
I did some research and tried adding a call to disable the stdout buffering by adding a call to:
setvbuf(stdout, NULL, _IONBF, 0);
just before calling execvp(...) in the parent process
so the relevant code looks now like this:
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);
}
With no luck.
Any ideas?
EDIT:
here is a sample of the parent code, the only thing needs changing is the path to the child executable:
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/wait.h>
#include <string>
#include <string.h>
#include <cstdio>
static int read_handle(-1);
static pid_t pid;
bool read_from_child(std::string& buff) {
fd_set rs;
timeval timeout;
memset(&rs, 0, sizeof(rs));
FD_SET(read_handle, &rs);
timeout.tv_sec = 1; // 1 second
timeout.tv_usec = 0;
int rc = select(read_handle+1, &rs, NULL, NULL, &timeout);
if ( rc == 0 ) {
// timeout
return true;
} else if ( rc > 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)) > 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, &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 < 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;
}
Actually, after struggling with it a bit, it seems like the only solution to this problem is by making the 'parent' process pretending to be a terminal using the OS pseudo terminal API calls.
One should call 'openpty()' before the fork(), and inside the child code, he should call 'login_tty(slave)' the slave is then becoming the stdin/out and stderr.
By pretending to a terminal, the buffering of stdout is automatically set to 'line mode' (i.e. flush occurs when \n is encountered). The parent should use the 'master' descriptor for readin/writing with the child process.
The modified parent code (in case anyone will ever need this):
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/wait.h>
#include <string>
#include <string.h>
#include <cstdio>
#include <pty.h>
#include <utmp.h>
static int read_handle(-1);
static pid_t pid;
bool read_from_child(std::string& buff) {
fd_set rs;
timeval timeout;
memset(&rs, 0, sizeof(rs));
FD_SET(read_handle, &rs);
timeout.tv_sec = 1; // 1 second
timeout.tv_usec = 0;
int rc = select(read_handle+1, &rs, NULL, NULL, &timeout);
if ( rc == 0 ) {
// timeout
return true;
} else if ( rc > 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)) > 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, &status, 0);
return false;
}
}
void execute() {
char *argv[] = {"/home/eran/devl/TestMain/Debug/TestMain", NULL};
int argc = 1;
int master, slave;
openpty(&master, &slave, NULL, NULL, NULL);
int rc = fork();
if ( rc == 0 ) {
login_tty(slave);
close(master);
// execute the process
if(execvp(argv[0], argv) != 0)
perror("execvp");
} else if ( rc < 0 ) {
perror("fork");
return;
} else {
// Parent
std::string buf;
close(slave);
read_handle = master;
while(read_from_child(buf)) {
if(buf.empty() == false) {
printf("Received: %s", buf.c_str());
}
buf.clear();
}
}
}
int main(int argc, char **argv) {
execute();
return 0;
}
Would inserting a call to fflush(stdout) after the printf not suffice?
Otherwise setvbuf should do the trick:
setvbuf(stdout,NULL,_IOLBF,0);
http://lists.gnu.org/archive/html/bug-coreutils/2008-11/msg00164.html
you can use LD_PRELOAD to setvbuf
If you ever need to achieve more control over the buffering of the child process, I made a module that expose features of the stdbuf preload trick, see this self answered question of mine:
C Control buffering of Child process