+
+// Helper function that checks whether the child with the given PID has exited
+// and fills the provided parameter with its return code if it did.
+bool CheckForChildExit(int pid, int* exitcodeOut)
+{
+ wxASSERT_MSG( pid > 0, "invalid PID" );
+
+ int status, rc;
+
+ // loop while we're getting EINTR
+ for ( ;; )
+ {
+ rc = waitpid(pid, &status, WNOHANG);
+
+ if ( rc != -1 || errno != EINTR )
+ break;
+ }
+
+ switch ( rc )
+ {
+ case 0:
+ // No error but the child is still running.
+ return false;
+
+ case -1:
+ // Checking child status failed. Invalid PID?
+ wxLogLastError(wxString::Format("waitpid(%d)", pid));
+ return false;
+
+ default:
+ // Child did terminate.
+ wxASSERT_MSG( rc == pid, "unexpected waitpid() return value" );
+
+ // notice that the caller expects the exit code to be signed, e.g. -1
+ // instead of 255 so don't assign WEXITSTATUS() to an int
+ signed char exitcode;
+ if ( WIFEXITED(status) )
+ exitcode = WEXITSTATUS(status);
+ else if ( WIFSIGNALED(status) )
+ exitcode = -WTERMSIG(status);
+ else
+ {
+ wxLogError("Child process (PID %d) exited for unknown reason, "
+ "status = %d", pid, status);
+ exitcode = -1;
+ }
+
+ if ( exitcodeOut )
+ *exitcodeOut = exitcode;
+
+ return true;
+ }
+}
+
+} // anonymous namespace
+
+wxExecuteData::ChildProcessesData wxExecuteData::ms_childProcesses;
+
+/* static */
+void wxExecuteData::OnSomeChildExited(int WXUNUSED(sig))
+{
+ // We know that some child process has terminated, but we don't know which
+ // one, so check all of them (notice that more than one could have exited).
+ //
+ // An alternative approach would be to call waitpid(-1, &status, WNOHANG)
+ // (in a loop to take care of the multiple children exiting case) and
+ // perhaps this would be more efficient. But for now this seems to work.
+
+
+ // Make a copy of the list before iterating over it to avoid problems due
+ // to deleting entries from it in the process.
+ const ChildProcessesData allChildProcesses = ms_childProcesses;
+ for ( ChildProcessesData::const_iterator it = allChildProcesses.begin();
+ it != allChildProcesses.end();
+ ++it )
+ {
+ const int pid = it->first;
+
+ // Check whether this child exited.
+ int exitcode;
+ if ( !CheckForChildExit(pid, &exitcode) )
+ continue;
+
+ // And handle its termination if it did.
+ //
+ // Notice that this will implicitly remove it from ms_childProcesses.
+ it->second->OnExit(exitcode);
+ }