forked from qt-creator/qt-creator
Debugger: Wait for terminal to finish after finishing debugger
When running process uses terminal, and the process is interrupted,
the d'tor of such process hangs on TerminalInterface::killStubProcess().
This shouldn't happen, and it should be addressed separately.
As a workaround we don't destroy the running terminal process,
but stop debugger first and wait for terminal to finish.
Amends 6d9575f942
Fixes: QTCREATORBUG-32721
Change-Id: I9612924973cfe97848758c3c688b9dbf20534a4d
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -130,11 +130,13 @@ class DebuggerRunToolPrivate
|
|||||||
public:
|
public:
|
||||||
ExecutableItem coreFileRecipe(const Storage<FilePath> &tempCoreFileStorage);
|
ExecutableItem coreFileRecipe(const Storage<FilePath> &tempCoreFileStorage);
|
||||||
ExecutableItem terminalRecipe(const SingleBarrier &barrier,
|
ExecutableItem terminalRecipe(const SingleBarrier &barrier,
|
||||||
const Storage<EnginesDriver> &driverStorage);
|
const Storage<EnginesDriver> &driverStorage,
|
||||||
|
const Storage<std::unique_ptr<Process>> &terminalStorage);
|
||||||
ExecutableItem fixupParamsRecipe();
|
ExecutableItem fixupParamsRecipe();
|
||||||
ExecutableItem debugServerRecipe(const SingleBarrier &barrier);
|
ExecutableItem debugServerRecipe(const SingleBarrier &barrier);
|
||||||
ExecutableItem startEnginesRecipe(const Storage<EnginesDriver> &driverStorage);
|
ExecutableItem startEnginesRecipe(const Storage<EnginesDriver> &driverStorage);
|
||||||
ExecutableItem finishEnginesRecipe(const Storage<EnginesDriver> &driverStorage);
|
ExecutableItem finalizeRecipe(const Storage<EnginesDriver> &driverStorage,
|
||||||
|
const Storage<std::unique_ptr<Process> > &terminalStorage);
|
||||||
|
|
||||||
DebuggerRunTool *q = nullptr;
|
DebuggerRunTool *q = nullptr;
|
||||||
DebuggerRunParameters m_runParameters;
|
DebuggerRunParameters m_runParameters;
|
||||||
@@ -193,54 +195,47 @@ ExecutableItem DebuggerRunToolPrivate::coreFileRecipe(const Storage<FilePath> &t
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExecutableItem DebuggerRunToolPrivate::terminalRecipe(const SingleBarrier &barrier,
|
ExecutableItem DebuggerRunToolPrivate::terminalRecipe(const SingleBarrier &barrier,
|
||||||
const Storage<EnginesDriver> &driverStorage)
|
const Storage<EnginesDriver> &driverStorage,
|
||||||
|
const Storage<std::unique_ptr<Process>> &terminalStorage)
|
||||||
{
|
{
|
||||||
const auto useTerminal = [this] {
|
const auto onSetup = [this, barrier, driverStorage, terminalStorage] {
|
||||||
const bool useCdbConsole = m_runParameters.cppEngineType() == CdbEngineType
|
const bool useCdbConsole = m_runParameters.cppEngineType() == CdbEngineType
|
||||||
&& (m_runParameters.startMode() == StartInternal
|
&& (m_runParameters.startMode() == StartInternal
|
||||||
|| m_runParameters.startMode() == StartExternal)
|
|| m_runParameters.startMode() == StartExternal)
|
||||||
&& settings().useCdbConsole();
|
&& settings().useCdbConsole();
|
||||||
if (useCdbConsole)
|
if (useCdbConsole)
|
||||||
m_runParameters.setUseTerminal(false);
|
m_runParameters.setUseTerminal(false);
|
||||||
return m_runParameters.useTerminal();
|
if (!m_runParameters.useTerminal()) {
|
||||||
};
|
barrier->barrier()->advance();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto onSetup = [this, barrier, driverStorage](Process &process) {
|
Process *process = new Process;
|
||||||
|
terminalStorage->reset(process);
|
||||||
ProcessRunData stub = m_runParameters.inferior();
|
ProcessRunData stub = m_runParameters.inferior();
|
||||||
if (m_runParameters.runAsRoot()) {
|
if (m_runParameters.runAsRoot()) {
|
||||||
process.setRunAsRoot(true);
|
process->setRunAsRoot(true);
|
||||||
RunControl::provideAskPassEntry(stub.environment);
|
RunControl::provideAskPassEntry(stub.environment);
|
||||||
}
|
}
|
||||||
process.setTerminalMode(TerminalMode::Debug);
|
process->setTerminalMode(TerminalMode::Debug);
|
||||||
process.setRunData(stub);
|
process->setRunData(stub);
|
||||||
|
|
||||||
QObject::connect(&process, &Process::started, &process,
|
QObject::connect(process, &Process::started, process,
|
||||||
[this, processPtr = &process, barrier = barrier->barrier()] {
|
[this, process, barrier = barrier->barrier()] {
|
||||||
m_runParameters.setApplicationPid(processPtr->processId());
|
m_runParameters.setApplicationPid(process->processId());
|
||||||
m_runParameters.setApplicationMainThreadId(processPtr->applicationMainThreadId());
|
m_runParameters.setApplicationMainThreadId(process->applicationMainThreadId());
|
||||||
barrier->advance();
|
barrier->advance();
|
||||||
});
|
});
|
||||||
|
|
||||||
EnginesDriver *driver = driverStorage.activeStorage();
|
EnginesDriver *driver = driverStorage.activeStorage();
|
||||||
QObject::connect(driver, &EnginesDriver::interruptTerminalRequested,
|
QObject::connect(driver, &EnginesDriver::interruptTerminalRequested,
|
||||||
&process, &Process::interrupt);
|
process, &Process::interrupt);
|
||||||
QObject::connect(driver, &EnginesDriver::kickoffTerminalProcessRequested,
|
QObject::connect(driver, &EnginesDriver::kickoffTerminalProcessRequested,
|
||||||
&process, &Process::kickoffProcess);
|
process, &Process::kickoffProcess);
|
||||||
};
|
process->start();
|
||||||
const auto onDone = [this](const Process &process, DoneWith result) {
|
|
||||||
if (result != DoneWith::Success)
|
|
||||||
q->reportFailure(process.errorString());
|
|
||||||
else
|
|
||||||
q->reportDone();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Group {
|
return Sync(onSetup);
|
||||||
If (useTerminal) >> Then {
|
|
||||||
ProcessTask(onSetup, onDone)
|
|
||||||
} >> Else {
|
|
||||||
Sync([barrier] { barrier->barrier()->advance(); })
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableItem DebuggerRunToolPrivate::fixupParamsRecipe()
|
ExecutableItem DebuggerRunToolPrivate::fixupParamsRecipe()
|
||||||
@@ -513,13 +508,31 @@ ExecutableItem DebuggerRunToolPrivate::startEnginesRecipe(const Storage<EnginesD
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutableItem DebuggerRunToolPrivate::finishEnginesRecipe(const Storage<EnginesDriver> &driverStorage)
|
static ExecutableItem terminalAwaiter(const Storage<std::unique_ptr<Process>> &terminalStorage)
|
||||||
|
{
|
||||||
|
return BarrierTask([terminalStorage](Barrier &barrier) {
|
||||||
|
QObject::connect(terminalStorage->get(), &Process::done, &barrier, &Barrier::advance,
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecutableItem DebuggerRunToolPrivate::finalizeRecipe(const Storage<EnginesDriver> &driverStorage,
|
||||||
|
const Storage<std::unique_ptr<Process>> &terminalStorage)
|
||||||
{
|
{
|
||||||
const auto isRunning = [driverStorage] { return driverStorage->isRunning(); };
|
const auto isRunning = [driverStorage] { return driverStorage->isRunning(); };
|
||||||
|
const auto isTerminalRunning = [terminalStorage] {
|
||||||
|
return terminalStorage->get() && terminalStorage->get()->isRunning();
|
||||||
|
};
|
||||||
|
|
||||||
return If (isRunning) >> Then {
|
return Group {
|
||||||
Sync([driverStorage] { driverStorage->stop(); }),
|
continueOnError,
|
||||||
doneAwaiter(driverStorage)
|
If (isRunning) >> Then {
|
||||||
|
Sync([driverStorage] { driverStorage->stop(); }),
|
||||||
|
doneAwaiter(driverStorage)
|
||||||
|
},
|
||||||
|
If (isTerminalRunning) >> Then {
|
||||||
|
terminalAwaiter(terminalStorage)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,6 +732,7 @@ void DebuggerRunTool::start()
|
|||||||
{
|
{
|
||||||
const Storage<EnginesDriver> driverStorage;
|
const Storage<EnginesDriver> driverStorage;
|
||||||
const Storage<FilePath> tempCoreFileStorage;
|
const Storage<FilePath> tempCoreFileStorage;
|
||||||
|
const Storage<std::unique_ptr<Process>> terminalStorage;
|
||||||
|
|
||||||
const auto onSetup = [this] {
|
const auto onSetup = [this] {
|
||||||
RunInterface *iface = runStorage().activeStorage();
|
RunInterface *iface = runStorage().activeStorage();
|
||||||
@@ -727,8 +741,8 @@ void DebuggerRunTool::start()
|
|||||||
d->m_runParameters.setAttachPid(runControl()->attachPid());
|
d->m_runParameters.setAttachPid(runControl()->attachPid());
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto terminalKicker = [this, driverStorage](const SingleBarrier &barrier) {
|
const auto terminalKicker = [this, driverStorage, terminalStorage](const SingleBarrier &barrier) {
|
||||||
return d->terminalRecipe(barrier, driverStorage);
|
return d->terminalRecipe(barrier, driverStorage, terminalStorage);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto debugServerKicker = [this](const SingleBarrier &barrier) {
|
const auto debugServerKicker = [this](const SingleBarrier &barrier) {
|
||||||
@@ -745,6 +759,7 @@ void DebuggerRunTool::start()
|
|||||||
const Group recipe {
|
const Group recipe {
|
||||||
runStorage(),
|
runStorage(),
|
||||||
driverStorage,
|
driverStorage,
|
||||||
|
terminalStorage,
|
||||||
tempCoreFileStorage,
|
tempCoreFileStorage,
|
||||||
continueOnError,
|
continueOnError,
|
||||||
onGroupSetup(onSetup),
|
onGroupSetup(onSetup),
|
||||||
@@ -757,7 +772,7 @@ void DebuggerRunTool::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.withCancel(canceler()),
|
}.withCancel(canceler()),
|
||||||
d->finishEnginesRecipe(driverStorage),
|
d->finalizeRecipe(driverStorage, terminalStorage),
|
||||||
onGroupDone(onDone)
|
onGroupDone(onDone)
|
||||||
};
|
};
|
||||||
d->m_taskTreeRunner.start(recipe, {}, [this](DoneWith result) {
|
d->m_taskTreeRunner.start(recipe, {}, [this](DoneWith result) {
|
||||||
|
Reference in New Issue
Block a user