QProcess issues after fork () and execv ()

I have a program that starts a workflow, waits for it to finish (listens for a signal SIGCHLD), and then starts another workflow. Inside my workflows, I run QProcessthat calls another program. In my test case, I call the touchstandard Linux command.

I use fork()and execv()to run workflows.

The problem is that it QProcessonly succeeds in the first workflow. After the advent of new workflows, he QProcessnever says that it was completed. The team touchitself does its job perfectly. But in all workflows except the first, he becomes a zombie at the end.

Here's the minimum test program:

#include <QCoreApplication>
#include <QProcess>
#include <QDebug>

#include <signal.h>
#include <wait.h>

void spawnWorkerProcess();
void launchQProcess();
void catchSigChild(int i);
void execChild();

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    if (argc > 1) // worker process
    {
        launchQProcess();
    }
    else // main process
    {
        if (signal(SIGCHLD, catchSigChild) == SIG_ERR)
        {
            qFatal("could not attach to SIGCHLD");
        }

        spawnWorkerProcess();

        return app.exec();
    }
}

void spawnWorkerProcess()
{
    pid_t pid = fork();
    if (pid == -1)
    {
        qCritical() << "FORK ERROR";
        exit(1);
    }
    else if (pid == 0)
    {
        /* the child process */
        execChild();
        exit(1);
    }
    else
    {
        qWarning() << "FORK OK";
    }
}


void
execChild()
{
    unsigned i = 0;
    const char **argv = new const char *[3];

    QByteArray ba = qApp->applicationFilePath().toLocal8Bit();
    argv[i++] = ba.data();
    argv[i++] = "worker";
    argv[i++] = 0;

    qWarning() << "execv ..."  << argv;
    execv(argv[0], const_cast<char *const *>(argv));
    qWarning() << "execv OK";

    delete[] argv;
}

void catchSigChild(int i)
{
    qCritical() << Q_FUNC_INFO << i;

    pid_t cpid;
    int stat;

    while ((cpid = waitpid(0, &stat, WNOHANG)) > 0)
    {
        static int counter = 0;

        counter++;

        if (counter < 5)
        {
            qDebug() << "SPAWN:" << counter;
            spawnWorkerProcess();
        }
        else
        {
            qCritical() << "RESPAWN LIMIT REACHED! Bye-bye!";
            exit(0);
        }
    }
}
void
launchQProcess()
{
    QProcess pr;

    qWarning() << "start QProcess " << qApp->applicationPid();
    pr.start(QString("touch /tmp/test/%1").arg(qApp->applicationPid()), 0);

    if (! pr.waitForFinished(3000))
    {
        qWarning() << "QProcess FAIL" << qApp->applicationPid() << pr.state() << "\n";

        delete (int*) 1; // we don't want to wait for QProcess timeout, so doing crash
    }
    else
    {
        qWarning() << "QProcess OK" << qApp->applicationPid() << pr.state() << "\n";
    }
}
+4
source share
1 answer

You should not make calls to glibc from a signal handler. Handlers are called asynchronously, which means they can interrupt system calls. These calls cannot be reentrant. To learn more about this, check the following page:

http://www.gnu.org/software/libc/manual/html_node/Nonreentrancy.html

+1
source

Source: https://habr.com/ru/post/1546100/


All Articles