Euller Borges
Euller Borges

Reputation: 91

How to determine the signal that terminated a QProcess with Qt4 on Linux?

I want to detect the QProcess I launched was terminated externally by either SIGKILL or SIGTERM. This is important in distinguishing between a crash (bug) and an external interference when I've written the process I'm launching myself.

I've tried registering watched processes through a slot connected to QProcess::started and setting a SIGCHLD handler (using sigaction) to capture the process status using waitpid. The issue is that waitpid clears the internal kernel data structure and even if I properly chain my handler to the one on the QProcess implementation, the latter isn't able to get the child status as any next calls to waitpid for that pid fail. Setting the process state to QProcess::ProcessState::NotRunning through QProcess::setProcessState avoids hanging on calls to waitForFinished in general, but there are corner cases which I couldn't manage to fix yet.

I was wondering if there isn't a better way to do this, other than modifying Qt's source code to store the status information somewhere.

Note: I know that crashes also terminate with a signal, which is SIGABRT. The main issue here is that a SIGKILL might tell me that the out of memory killer in Linux was the responsible for the process termination.

Upvotes: 0

Views: 365

Answers (2)

Euller Borges
Euller Borges

Reputation: 91

The solution altering Qt's code under Qt 4, basically involves a simple modification to QProcessPrivate::waitForDeadChild():

if (qt_safe_waitpid(pid_t(pid), &exitStatus, WNOHANG) > 0) {
         processManager()->remove(q);
         crashed = !WIFEXITED(exitStatus);
-        exitCode = WEXITSTATUS(exitStatus);
+        exitCode = crashed ? WTERMSIG(exitStatus) : WEXITSTATUS(exitStatus);

The signal will then be available on QProcess::exitCode() after QProcess::finished() has been emitted.

Note: Qt5 is using Thiago Macieira's forkfd, so this solution won't work.

Upvotes: 0

Chen
Chen

Reputation: 11

This is my code, friend.

QProcess* pExe = new QProcess(this);
connect(pExe, SIGNAL(finished(int, QProcess::ExitStatus)), this,  SLOT(onOSRExit(int, QProcess::ExitStatus)));
pExe->setWorkingDirectory(QCoreApplication::applicationDirPath());
pExe->start("some.exe");

....

void CXXXXX::onOSRExit(int exitCode, QProcess::ExitStatus exitStatus)
{
}

Upvotes: 0

Related Questions