Changeset View
Changeset View
Standalone View
Standalone View
src/backtracegenerator.cpp
Show All 31 Lines | |||||
32 | #include <KShell> | 32 | #include <KShell> | ||
33 | #include <KProcess> | 33 | #include <KProcess> | ||
34 | 34 | | |||
35 | #include "parser/backtraceparser.h" | 35 | #include "parser/backtraceparser.h" | ||
36 | 36 | | |||
37 | BacktraceGenerator::BacktraceGenerator(const Debugger & debugger, QObject *parent) | 37 | BacktraceGenerator::BacktraceGenerator(const Debugger & debugger, QObject *parent) | ||
38 | : QObject(parent), | 38 | : QObject(parent), | ||
39 | m_debugger(debugger), m_proc(nullptr), | 39 | m_debugger(debugger), m_proc(nullptr), | ||
40 | m_temp(nullptr), m_state(NotLoaded) | 40 | m_temp(nullptr), m_state(NotLoaded), | ||
41 | m_lldbDetached(false) | ||||
41 | { | 42 | { | ||
42 | m_parser = BacktraceParser::newParser(m_debugger.codeName(), this); | 43 | m_parser = BacktraceParser::newParser(m_debugger.codeName(), this); | ||
43 | m_parser->connectToGenerator(this); | 44 | m_parser->connectToGenerator(this); | ||
44 | 45 | | |||
45 | #ifdef BACKTRACE_PARSER_DEBUG | 46 | #ifdef BACKTRACE_PARSER_DEBUG | ||
46 | m_debugParser = BacktraceParser::newParser(QString(), this); //uses the null parser | 47 | m_debugParser = BacktraceParser::newParser(QString(), this); //uses the null parser | ||
47 | m_debugParser->connectToGenerator(this); | 48 | m_debugParser->connectToGenerator(this); | ||
48 | #endif | 49 | #endif | ||
49 | } | 50 | } | ||
50 | 51 | | |||
51 | BacktraceGenerator::~BacktraceGenerator() | 52 | BacktraceGenerator::~BacktraceGenerator() | ||
52 | { | 53 | { | ||
53 | if (m_proc && m_proc->state() == QProcess::Running) { | 54 | if (m_proc && m_proc->state() == QProcess::Running) { | ||
54 | qCWarning(DRKONQI_LOG) << "Killing running debugger instance"; | 55 | qCWarning(DRKONQI_LOG) << "Killing running debugger instance"; | ||
55 | m_proc->disconnect(this); | 56 | m_proc->disconnect(this); | ||
56 | m_proc->terminate(); | 57 | m_proc->terminate(); | ||
57 | if (!m_proc->waitForFinished(10000)) { | 58 | if (!m_proc->waitForFinished(10000)) { | ||
58 | m_proc->kill(); | 59 | m_proc->kill(); | ||
59 | m_proc->waitForFinished(); | 60 | // lldb can become "stuck" on OS X; just mark m_proc as to be deleted later rather | ||
60 | } | 61 | // than waiting a potentially very long time for it to heed the kill() request. | ||
62 | m_proc->deleteLater(); | ||||
63 | } else { | ||||
61 | delete m_proc; | 64 | delete m_proc; | ||
65 | } | ||||
62 | delete m_temp; | 66 | delete m_temp; | ||
63 | } | 67 | } | ||
64 | } | 68 | } | ||
65 | 69 | | |||
66 | bool BacktraceGenerator::start() | 70 | bool BacktraceGenerator::start() | ||
67 | { | 71 | { | ||
68 | //they should always be null before entering this function. | 72 | //they should always be null before entering this function. | ||
69 | Q_ASSERT(!m_proc); | 73 | Q_ASSERT(!m_proc); | ||
Show All 21 Lines | |||||
91 | 95 | | |||
92 | // start the debugger | 96 | // start the debugger | ||
93 | QString str = m_debugger.command(); | 97 | QString str = m_debugger.command(); | ||
94 | Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); | 98 | Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); | ||
95 | 99 | | |||
96 | *m_proc << KShell::splitArgs(str); | 100 | *m_proc << KShell::splitArgs(str); | ||
97 | m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); | 101 | m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); | ||
98 | m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); | 102 | m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); | ||
103 | // check if the debugger should take its input from a file we'll generate, | ||||
104 | // and take the appropriate steps if so | ||||
105 | QString stdinFile = m_debugger.backendValueOfParameter(QStringLiteral("ExecInputFile")); | ||||
106 | Debugger::expandString(stdinFile, Debugger::ExpansionUsageShell, m_temp->fileName()); | ||||
107 | if (!stdinFile.isEmpty() && QFile::exists(stdinFile)) { | ||||
108 | m_proc->setStandardInputFile(stdinFile); | ||||
109 | } | ||||
99 | connect(m_proc, &KProcess::readyReadStandardOutput, this, &BacktraceGenerator::slotReadInput); | 110 | connect(m_proc, &KProcess::readyReadStandardOutput, this, &BacktraceGenerator::slotReadInput); | ||
100 | connect(m_proc, static_cast<void (KProcess::*)(int, QProcess::ExitStatus)>(&KProcess::finished), this, &BacktraceGenerator::slotProcessExited); | 111 | connect(m_proc, static_cast<void (KProcess::*)(int, QProcess::ExitStatus)>(&KProcess::finished), this, &BacktraceGenerator::slotProcessExited); | ||
101 | 112 | | |||
113 | m_lldbDetached = false; | ||||
102 | m_proc->start(); | 114 | m_proc->start(); | ||
103 | if (!m_proc->waitForStarted()) { | 115 | if (!m_proc->waitForStarted()) { | ||
104 | //we mustn't keep these around... | 116 | //we mustn't keep these around... | ||
105 | m_proc->deleteLater(); | 117 | m_proc->deleteLater(); | ||
106 | m_temp->deleteLater(); | 118 | m_temp->deleteLater(); | ||
107 | m_proc = nullptr; | 119 | m_proc = nullptr; | ||
108 | m_temp = nullptr; | 120 | m_temp = nullptr; | ||
109 | 121 | | |||
110 | m_state = FailedToStart; | 122 | m_state = FailedToStart; | ||
111 | emit failedToStart(); | 123 | emit failedToStart(); | ||
112 | return false; | 124 | return false; | ||
113 | } | 125 | } | ||
114 | 126 | | |||
115 | return true; | 127 | return true; | ||
116 | } | 128 | } | ||
117 | 129 | | |||
118 | void BacktraceGenerator::slotReadInput() | 130 | void BacktraceGenerator::slotReadInput() | ||
119 | { | 131 | { | ||
132 | if (m_lldbDetached) { | ||||
133 | return; | ||||
134 | } | ||||
135 | | ||||
120 | // we do not know if the output array ends in the middle of an utf-8 sequence | 136 | // we do not know if the output array ends in the middle of an utf-8 sequence | ||
121 | m_output += m_proc->readAllStandardOutput(); | 137 | m_output += m_proc->readAllStandardOutput(); | ||
122 | 138 | | |||
123 | int pos; | 139 | int pos; | ||
124 | while ((pos = m_output.indexOf('\n')) != -1) { | 140 | while ((pos = m_output.indexOf('\n')) != -1 && m_proc->state() == QProcess::Running) { | ||
davidedmundson: this seems dangerous for the other clients.
It's not unfeasible for a process to have a load… | |||||
You mean move the check on QProcess::Running into the if (line.startsWith(QLatin1String("Process ")) && line.endsWith(QLatin1String(" detached"))) ? rjvbb: You mean move the check on QProcess::Running into the `if (line.startsWith(QLatin1String… | |||||
davidedmundson: Yes
Also is it worth adding a "break;" there? | |||||
A break instead of or in addition to the return? I think I'd prefer the return, unless you think that maybe someday there will be some extra steps to be taken after the while loop? rjvbb: A break instead of or in addition to the return? I think I'd prefer the return, unless you… | |||||
125 | QString line = QString::fromLocal8Bit(m_output.constData(), pos + 1); | 141 | QString line = QString::fromLocal8Bit(m_output.constData(), pos + 1); | ||
126 | m_output.remove(0, pos + 1); | 142 | m_output.remove(0, pos + 1); | ||
127 | 143 | | |||
128 | emit newLine(line); | 144 | emit newLine(line); | ||
145 | line = line.simplified(); | ||||
146 | if (line.startsWith(QLatin1String("Process ")) && line.endsWith(QLatin1String(" detached"))) { | ||||
147 | // Anything following this line doesn't interest us, and lldb has been known | ||||
148 | // to turn into a zombie instead of exitting, thereby blocking us. | ||||
149 | m_lldbDetached = true; | ||||
150 | m_proc->terminate(); | ||||
151 | if (!m_proc->waitForFinished(500)) { | ||||
152 | m_proc->kill(); | ||||
153 | } | ||||
154 | slotProcessExited(0, QProcess::NormalExit); | ||||
155 | return; | ||||
156 | } | ||||
129 | } | 157 | } | ||
130 | } | 158 | } | ||
131 | 159 | | |||
132 | void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) | 160 | void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) | ||
133 | { | 161 | { | ||
134 | //these are useless now | 162 | //these are useless now | ||
135 | m_proc->deleteLater(); | 163 | m_proc->deleteLater(); | ||
136 | m_temp->deleteLater(); | 164 | m_temp->deleteLater(); | ||
Show All 29 Lines |
this seems dangerous for the other clients.
It's not unfeasible for a process to have a load of data still in the buffer when it quits.
I don't know lldb, but it seems you can probably move this to ~149