Changeset View
Standalone View
drkonqi/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(NULL), | 39 | m_debugger(debugger), m_proc(NULL), | ||
40 | m_temp(NULL), m_state(NotLoaded) | 40 | m_temp(NULL), 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 | qWarning() << "Killing running debugger instance"; | 55 | qWarning() << "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(); | ||
60 | // NB: lldb can get stuck here, a waitForFinished() without timeout is safe | ||||
61 | // only if lldbrc's BatchCommand ends with something like "\nimport os ; os._exit(0)\nquit" | ||||
59 | m_proc->waitForFinished(); | 62 | m_proc->waitForFinished(); | ||
kfunk: Please do this only if `lldb` is used then. No need to change code which apparently worked… | |||||
It's been a while, QProcess::terminate() was an approach I remember preferring to avoid possibly because it also led to runtime warnings. I also don't think there's much of a difference in what ::kill() and ::terminate() do. rjvbb: It's been a while, QProcess::terminate() was an approach I remember preferring to avoid… | |||||
rjvbb: Re (sic:) KProcess::terminate(): see the hunk around line 145! | |||||
60 | } | 63 | } | ||
61 | delete m_proc; | 64 | delete m_proc; | ||
62 | delete m_temp; | 65 | delete m_temp; | ||
63 | } | 66 | } | ||
64 | } | 67 | } | ||
65 | 68 | | |||
66 | bool BacktraceGenerator::start() | 69 | bool BacktraceGenerator::start() | ||
67 | { | 70 | { | ||
Show All 22 Lines | |||||
90 | 93 | | |||
91 | // start the debugger | 94 | // start the debugger | ||
92 | QString str = m_debugger.command(); | 95 | QString str = m_debugger.command(); | ||
93 | Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); | 96 | Debugger::expandString(str, Debugger::ExpansionUsageShell, m_temp->fileName()); | ||
94 | 97 | | |||
95 | *m_proc << KShell::splitArgs(str); | 98 | *m_proc << KShell::splitArgs(str); | ||
96 | m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); | 99 | m_proc->setOutputChannelMode(KProcess::OnlyStdoutChannel); | ||
97 | m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); | 100 | m_proc->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Text); | ||
101 | // check if the debugger should take its input from a file we'll generate, | ||||
102 | // and take the appropriate steps if so | ||||
103 | QString stdinFile = m_debugger.backendValueOfParameter(QStringLiteral("ExecInputFile")); | ||||
104 | Debugger::expandString(stdinFile, Debugger::ExpansionUsageShell, m_temp->fileName()); | ||||
105 | if (!stdinFile.isEmpty() && QFile::exists(stdinFile)) { | ||||
106 | m_proc->setStandardInputFile(stdinFile); | ||||
107 | } | ||||
98 | connect(m_proc, &KProcess::readyReadStandardOutput, this, &BacktraceGenerator::slotReadInput); | 108 | connect(m_proc, &KProcess::readyReadStandardOutput, this, &BacktraceGenerator::slotReadInput); | ||
99 | connect(m_proc, static_cast<void (KProcess::*)(int, QProcess::ExitStatus)>(&KProcess::finished), this, &BacktraceGenerator::slotProcessExited); | 109 | connect(m_proc, static_cast<void (KProcess::*)(int, QProcess::ExitStatus)>(&KProcess::finished), this, &BacktraceGenerator::slotProcessExited); | ||
100 | 110 | | |||
111 | m_lldbDetached = false; | ||||
101 | m_proc->start(); | 112 | m_proc->start(); | ||
102 | if (!m_proc->waitForStarted()) { | 113 | if (!m_proc->waitForStarted()) { | ||
103 | //we mustn't keep these around... | 114 | //we mustn't keep these around... | ||
104 | m_proc->deleteLater(); | 115 | m_proc->deleteLater(); | ||
105 | m_temp->deleteLater(); | 116 | m_temp->deleteLater(); | ||
106 | m_proc = NULL; | 117 | m_proc = NULL; | ||
107 | m_temp = NULL; | 118 | m_temp = NULL; | ||
108 | 119 | | |||
109 | m_state = FailedToStart; | 120 | m_state = FailedToStart; | ||
110 | emit failedToStart(); | 121 | emit failedToStart(); | ||
111 | return false; | 122 | return false; | ||
112 | } | 123 | } | ||
113 | 124 | | |||
114 | return true; | 125 | return true; | ||
115 | } | 126 | } | ||
116 | 127 | | |||
117 | void BacktraceGenerator::slotReadInput() | 128 | void BacktraceGenerator::slotReadInput() | ||
118 | { | 129 | { | ||
130 | if (m_lldbDetached) { | ||||
131 | return; | ||||
132 | } | ||||
133 | | ||||
119 | // we do not know if the output array ends in the middle of an utf-8 sequence | 134 | // we do not know if the output array ends in the middle of an utf-8 sequence | ||
120 | m_output += m_proc->readAllStandardOutput(); | 135 | m_output += m_proc->readAllStandardOutput(); | ||
121 | 136 | | |||
122 | int pos; | 137 | int pos; | ||
123 | while ((pos = m_output.indexOf('\n')) != -1) { | 138 | while ((pos = m_output.indexOf('\n')) != -1 && m_proc->state() == QProcess::Running) { | ||
124 | QString line = QString::fromLocal8Bit(m_output, pos + 1); | 139 | QString line = QString::fromLocal8Bit(m_output, pos + 1); | ||
125 | m_output.remove(0, pos + 1); | 140 | m_output.remove(0, pos + 1); | ||
126 | 141 | | |||
127 | emit newLine(line); | 142 | emit newLine(line); | ||
143 | line = line.simplified(); | ||||
144 | if (line.startsWith(QLatin1String("Process ")) && line.endsWith(QLatin1String(" detached"))) { | ||||
This whole logic looks really cumbersome. Is there really no way to exit LLDB cleanly after detach? http://stackoverflow.com/questions/26267289/how-can-i-exit-lldb-after-running-commands-with-o suggests there is: lldb /bin/ls -o "run" -o "script import os; os._exit(1)" I take it not everyone's got Python on they system, but this works for me as well: lldb -p $(pidof kate) -o detach -o quit Just put that into the -o quit in the lldbrc? kfunk: This whole logic looks really cumbersome.
Is there really no way to exit LLDB cleanly after… | |||||
-o quit indeed works with newer lldb versions, but not yet with the system version on OS X 10.9 . I suppose I could do a combination of both. The logical way would be \nquit\nscript import os; os._exit(0) but processing stops after the quit command so it'd have to be the opposite. I'd have to test this for a bit. Not having a python interpreter may not be an issue. I don't know how its complete absence is treated but errors in the python expression (loading an inexisting module for instance) don't stop processing of subsequent commands. Can one put comments in the lldbrc file explaining the reason of the surprising BatchCommands set? rjvbb: `-o quit` indeed works with newer lldb versions, but not yet with the system version on OS X 10. | |||||
145 | // Anything following this line doesn't interest us and shouldn't show in the backtrace. | ||||
146 | m_lldbDetached = true; | ||||
147 | // Also, lldb has been known to turn into a zombie instead of exitting, thereby blocking us. | ||||
148 | // Recent versions should react correctly to the quit or else to the Python os._exit() commands | ||||
149 | // in lldbrc and we will thus assume that the application has terminated. | ||||
150 | // (see also http://stackoverflow.com/questions/26267289/how-can-i-exit-lldb-after-running-commands-with-o) | ||||
151 | if (!m_proc->waitForFinished(500)) { | ||||
152 | m_proc->kill(); | ||||
153 | } | ||||
154 | slotProcessExited(0, QProcess::NormalExit); | ||||
155 | // either way we should stop reading now. | ||||
156 | return; | ||||
157 | } | ||||
128 | } | 158 | } | ||
129 | } | 159 | } | ||
130 | 160 | | |||
131 | void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) | 161 | void BacktraceGenerator::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus) | ||
132 | { | 162 | { | ||
133 | //these are useless now | 163 | //these are useless now | ||
134 | m_proc->deleteLater(); | 164 | m_proc->deleteLater(); | ||
135 | m_temp->deleteLater(); | 165 | m_temp->deleteLater(); | ||
Show All 29 Lines |
Please do this only if lldb is used then. No need to change code which apparently worked fine for years. Also, did you try QProcess::terminate instead?
PS: QProcess gets unhappy when being deleted while still running (=> runtime warnings).
PPS: Please read my other advice about quitting LLDB below, too