int ConsoleFinder::RunConsole(const wxString &title) { // start the xterm and put the shell to sleep with -e sleep 80000 // fetch the xterm tty so we can issue to gdb a "tty /dev/pts/#" // redirecting program stdin/stdout/stderr to the xterm console. #ifndef __WXMSW__ wxString cmd; cmd = GetConsoleCommand(); cmd.Replace(wxT("$(TITLE)"), title); cmd.Replace(wxT("$(CMD)"), wxString::Format(wxT("sleep %lu"), 80000 + wxGetProcessId())); wxLogMessage(wxString::Format(wxT("Launching console: %s"), cmd.c_str())); m_nConsolePid = wxExecute(cmd, wxEXEC_ASYNC|wxEXEC_MAKE_GROUP_LEADER); if (m_nConsolePid <= 0) { return -1; } // Issue the PS command to get the /dev/tty device name // First, wait for the xterm to settle down, else PS won't see the sleep task wxSleep(1); m_ConsoleTty = GetConsoleTty(m_nConsolePid); if (m_ConsoleTty.IsEmpty()) { FreeConsole(); return -1; } return m_nConsolePid; #else //__WXMSW__ wxUnusedVar(title); return -1; #endif }
int cbDebuggerPlugin::RunNixConsole(wxString &consoleTty) { consoleTty = wxEmptyString; #ifndef __WXMSW__ // Start a terminal and put the shell to sleep with -e sleep 80000. // Fetch the terminal's tty, so we can tell the debugger what TTY to use, // thus redirecting program's stdin/stdout/stderr to the terminal. wxString cmd; int consolePid = 0; // Use the terminal specified by the user in the Settings -> Environment. wxString term = Manager::Get()->GetConfigManager(_T("app"))->Read(_T("/console_terminal"), DEFAULT_CONSOLE_TERM); term.Replace(_T("$TITLE"), wxString(wxT("'"))+_("Program Console")+wxT("'")); cmd << term << _T(" "); const wxString &sleepCommand = MakeSleepCommand(); cmd << sleepCommand; Manager::Get()->GetMacrosManager()->ReplaceEnvVars(cmd); // The lifetime of wxProcess objects is very uncertain, so we are using a shared pointer to // prevent us accessing deleted objects. cb::shared_ptr<ConsoleProcessTerminationInfo> processInfo(new ConsoleProcessTerminationInfo); ConsoleProcess *process = new ConsoleProcess(processInfo); consolePid = wxExecute(cmd, wxEXEC_ASYNC, process); if (consolePid <= 0) return -1; // Try to find the TTY. We're using a loop, because some slow machines might make the check fail due // to a slow starting terminal. for (int ii = 0; ii < 100; ++ii) { // First, wait for the terminal to settle down, else PS won't see the sleep task Manager::Yield(); ::wxMilliSleep(200); // Try to detect if the terminal command is present or its parameters are valid. if (processInfo->FailedToStart() /*&& ii > 0*/) { Log(F(wxT("Failed to execute terminal command: '%s' (exit code: %d)"), cmd.wx_str(), processInfo->status), Logger::error); break; } // Try to find tty path and pid for the sleep command we've just executed. const ConsoleInfo &info = GetConsoleTty(consolePid); // If there is no sleep command yet, do another iteration after a small delay. if (!info.IsValid()) continue; // Try to find if the console window is still alive. Newer terminals like gnome-terminal // try to be easier on resources and use a shared server process. For these terminals the // spawned terminal process exits immediately, but the sleep command is still executed. // If we detect such case we will return the PID for the sleep command instead of the PID // for the terminal. if (kill(consolePid, 0) == -1 && errno == ESRCH) { DebugLog(F(wxT("Using sleep command's PID as console PID %d, TTY %s"), info.sleepPID, info.ttyPath.wx_str())); consoleTty = info.ttyPath; return info.sleepPID; } else { DebugLog(F(wxT("Using terminal's PID as console PID %d, TTY %s"), info.sleepPID, info.ttyPath.wx_str())); consoleTty = info.ttyPath; return consolePid; } } // failed to find the console tty if (consolePid != 0) ::wxKill(consolePid); #endif // !__WWXMSW__ return -1; }