Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
There is an external program I'm calling from within my C/C++ program, by using fork() and execl(), and redirecting the stdio with dup2() to be able to read the output from the external program. I...
#2: Post edited
There is an external program I'm calling from within my C/C++ program, by using fork() and execl(), and also tapping the stdio with dup2() to be able to read the output from the external program.- It's based on this code:
- [A simple popen2 implementation](https://dzone.com/articles/simple-popen2-implementation)
- In another thread just started, the timeout handling is done.
- Then I make calls to read() on the out file handle, in a loop, writing what's read to a stream.
- Now that external program waits for something on the system to happen - which might not happen, so after a while, I'd like to call it a timeout and end the child process (from the extra thread).
- Whether sending SIGTERM or SIGKILL, changing the order of closing file handles w.r.t. to that, the result is always that the last call to read() hangs forever.
- Added: Seems even if the process exits in time, the read() hangs. That did not happen when I used the regular popen() to start the process instead of popen**2**(), but since I need the PID to terminate the process, I'm using the latter.
- I have found discussions about a problem with read() in a somewhat similar situation, and it was suggested that the SIGCHLD must be ignored in the parent process. That doesn't help, though.
- Is there something wrong per se in doing things this way, that cause this read() to hang?
- ```
- int exec_proc2(std::string cmd, std::ostream & outputStream, unsigned timeoutMilsecs)
- {
- constexpr int bufsize = 128;
- std::array<char, bufsize> buffer;
- int inf, outf;
- auto pid = popen2( cmd.c_str(), &inf, &outf );
- close( inf ); // writing to process not used, we're only reading
- if (pid < 0)
- { close( outf );
- return -1;
- }
- std::atomic<bool> notDone = true;
- std::atomic<bool> timedOut = false;
- thread timeoutTask( [&]
- { TimeoutWatch tw(timeoutMilsecs, true);
- while (notDone && !tw.TimedOut())
- { sleep(0.1);
- }
- if (tw.TimedOut())
- { close( outf );
- int ret = kill( pid, SIGKILL );
- if (ret != 0)
- { // this never failed so far
- }
- notDone = false;
- cout << "DBG: TIMEOUT@exec_proc2" << endl; // this is always printed after the timeout time
- timedOut = true;
- }
- } );
- size_t count;
- do
- { if ((count = read( outf, buffer.data(), bufsize )) > 0)
- { outputStream.write( buffer.data(), count );
- }
- } while(count > 0 && !timedOut);
- cout << "DBG: joining...@exec_proc2" << endl; // this line is never printed, so it hangs above already
- notDone = false; // for the case that the read() loop exits earlier than the timeout thread: tell the thread it's over
- timeoutTask.join();
- close( outf );
- return timedOut ? -2 : 0;
- }
- ```
- There is an external program I'm calling from within my C/C++ program, by using fork() and execl(), and redirecting the stdio with dup2() to be able to read the output from the external program.
- It's based on this code:
- [A simple popen2 implementation](https://dzone.com/articles/simple-popen2-implementation)
- In another thread just started, the timeout handling is done.
- Then I make calls to read() on the out file handle, in a loop, writing what's read to a stream.
- Now that external program waits for something on the system to happen - which might not happen, so after a while, I'd like to call it a timeout and end the child process (from the extra thread).
- Whether sending SIGTERM or SIGKILL, changing the order of closing file handles w.r.t. to that, the result is always that the last call to read() hangs forever.
- Added: Seems even if the process exits in time, the read() hangs. That did not happen when I used the regular popen() to start the process instead of popen**2**(), but since I need the PID to terminate the process, I'm using the latter.
- I have found discussions about a problem with read() in a somewhat similar situation, and it was suggested that the SIGCHLD must be ignored in the parent process. That doesn't help, though.
- Is there something wrong per se in doing things this way, that cause this read() to hang?
- ```
- int exec_proc2(std::string cmd, std::ostream & outputStream, unsigned timeoutMilsecs)
- {
- constexpr int bufsize = 128;
- std::array<char, bufsize> buffer;
- int inf, outf;
- auto pid = popen2( cmd.c_str(), &inf, &outf );
- close( inf ); // writing to process not used, we're only reading
- if (pid < 0)
- { close( outf );
- return -1;
- }
- std::atomic<bool> notDone = true;
- std::atomic<bool> timedOut = false;
- thread timeoutTask( [&]
- { TimeoutWatch tw(timeoutMilsecs, true);
- while (notDone && !tw.TimedOut())
- { sleep(0.1);
- }
- if (tw.TimedOut())
- { close( outf );
- int ret = kill( pid, SIGKILL );
- if (ret != 0)
- { // this never failed so far
- }
- notDone = false;
- cout << "DBG: TIMEOUT@exec_proc2" << endl; // this is always printed after the timeout time
- timedOut = true;
- }
- } );
- size_t count;
- do
- { if ((count = read( outf, buffer.data(), bufsize )) > 0)
- { outputStream.write( buffer.data(), count );
- }
- } while(count > 0 && !timedOut);
- cout << "DBG: joining...@exec_proc2" << endl; // this line is never printed, so it hangs above already
- notDone = false; // for the case that the read() loop exits earlier than the timeout thread: tell the thread it's over
- timeoutTask.join();
- close( outf );
- return timedOut ? -2 : 0;
- }
- ```
#1: Initial revision
How kill a child process without read() hanging in the parent process?
There is an external program I'm calling from within my C/C++ program, by using fork() and execl(), and also tapping the stdio with dup2() to be able to read the output from the external program. It's based on this code: [A simple popen2 implementation](https://dzone.com/articles/simple-popen2-implementation) In another thread just started, the timeout handling is done. Then I make calls to read() on the out file handle, in a loop, writing what's read to a stream. Now that external program waits for something on the system to happen - which might not happen, so after a while, I'd like to call it a timeout and end the child process (from the extra thread). Whether sending SIGTERM or SIGKILL, changing the order of closing file handles w.r.t. to that, the result is always that the last call to read() hangs forever. Added: Seems even if the process exits in time, the read() hangs. That did not happen when I used the regular popen() to start the process instead of popen**2**(), but since I need the PID to terminate the process, I'm using the latter. I have found discussions about a problem with read() in a somewhat similar situation, and it was suggested that the SIGCHLD must be ignored in the parent process. That doesn't help, though. Is there something wrong per se in doing things this way, that cause this read() to hang? ``` int exec_proc2(std::string cmd, std::ostream & outputStream, unsigned timeoutMilsecs) { constexpr int bufsize = 128; std::array<char, bufsize> buffer; int inf, outf; auto pid = popen2( cmd.c_str(), &inf, &outf ); close( inf ); // writing to process not used, we're only reading if (pid < 0) { close( outf ); return -1; } std::atomic<bool> notDone = true; std::atomic<bool> timedOut = false; thread timeoutTask( [&] { TimeoutWatch tw(timeoutMilsecs, true); while (notDone && !tw.TimedOut()) { sleep(0.1); } if (tw.TimedOut()) { close( outf ); int ret = kill( pid, SIGKILL ); if (ret != 0) { // this never failed so far } notDone = false; cout << "DBG: TIMEOUT@exec_proc2" << endl; // this is always printed after the timeout time timedOut = true; } } ); size_t count; do { if ((count = read( outf, buffer.data(), bufsize )) > 0) { outputStream.write( buffer.data(), count ); } } while(count > 0 && !timedOut); cout << "DBG: joining...@exec_proc2" << endl; // this line is never printed, so it hangs above already notDone = false; // for the case that the read() loop exits earlier than the timeout thread: tell the thread it's over timeoutTask.join(); close( outf ); return timedOut ? -2 : 0; } ```