+#if wxUSE_CONSOLE_EVENTLOOP
+ wxConsoleEventLoop loop;
+ return RunLoopUntilChildExit(execData, loop);
+#else // !wxUSE_CONSOLE_EVENTLOOP
+ wxFAIL_MSG( wxS("Can't wait for child process without wxConsoleEventLoop") );
+
+ return -1;
+#endif // wxUSE_CONSOLE_EVENTLOOP/!wxUSE_CONSOLE_EVENTLOOP
+}
+
+// This function is common code for both console and GUI applications and used
+// by wxExecute() to wait for the child exit while dispatching events.
+//
+// Notice that it should not be used for all the other cases, e.g. when we
+// don't need to wait for the child (wxEXEC_ASYNC) or when the events must not
+// dispatched (wxEXEC_NOEVENTS).
+int
+wxAppTraits::RunLoopUntilChildExit(wxExecuteData& execData,
+ wxEventLoopBase& loop)
+{
+ // It is possible that wxExecuteData::OnExit() had already been called
+ // and reset the PID to 0, in which case we don't need to do anything
+ // at all.
+ if ( !execData.pid )
+ return execData.exitcode;
+
+#if wxUSE_STREAMS
+ // Monitor the child streams if necessary.
+ wxScopedPtr<wxEventLoopSourceHandler>
+ stdoutHandler,
+ stderrHandler;
+ if ( execData.IsRedirected() )
+ {
+ stdoutHandler.reset(new wxExecuteEventLoopSourceHandler
+ (
+ execData.fdOut, execData.bufOut
+ ));
+ stderrHandler.reset(new wxExecuteEventLoopSourceHandler
+ (
+ execData.fdErr, execData.bufErr
+ ));
+ }
+#endif // wxUSE_STREAMS
+
+ // Store the event loop in the data associated with the child
+ // process so that it could exit the loop when the child exits.
+ execData.syncEventLoop = &loop;
+
+ // And run it.
+ loop.Run();
+
+ // The exit code will have been set when the child termination was detected.
+ return execData.exitcode;
+}
+
+// ----------------------------------------------------------------------------
+// wxExecuteData
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// 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;
+ }