Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QProcess becomes non-responsive with negative return value from Windows console app
QtWS25 Last Chance

QProcess becomes non-responsive with negative return value from Windows console app

Scheduled Pinned Locked Moved General and Desktop
6 Posts 2 Posters 3.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    dancingbeartech
    wrote on last edited by
    #1

    I have the following situation.

    QProcess (either stack or heap) with appropriate finish and error connections made, call start on a Windows console application. If the application returns a non-negative value, everything is okay.

    If the console application returns a negative value, my spawning application crashes in QProcessPrivate::cleanup() at CloseHandle(pid->hThread)

    Is this a bug in QProcess, or an misunderstanding of something regarding return values?

    Thanks.

    1 Reply Last reply
    0
    • M Offline
      M Offline
      MuldeR
      wrote on last edited by
      #2

      Please show how you are using QPorcess in your code...

      My OpenSource software at: http://muldersoft.com/

      Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

      Go visit the coop: http://youtu.be/Jay...

      1 Reply Last reply
      0
      • D Offline
        D Offline
        dancingbeartech
        wrote on last edited by
        #3

        Yes, here we go:

        Excerpted from class header:

        @
        public slots:
        // methods
        void RunNextWavelength(int exitCode, QProcess::ExitStatus exitStatus);
        void ReconProcessError(QProcess::ProcessError error);

        private:
        // interpret exitStatus for user display
        QString UserMessageFromExitStatus(int status);

        // QProcess to run recon
        QProcess m_recon_proc;
        

        @

        From ctor/dtor:

        @
        CNexusReconJob::CNexusReconJob():
        /* ... initialization list ... */
        {
        connect(&m_recon_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(RunNextWavelength(int, QProcess::ExitStatus)));
        connect(&m_recon_proc, SIGNAL(error(QProcess::ProcessError)),
        this, SLOT(ReconProcessError(QProcess::ProcessError)));
        connect(this, SIGNAL(KillRunningJob()),
        &m_recon_proc, SLOT(kill()));
        }

        CNexusReconJob::~CNexusReconJob()
        {
        disconnect(&m_recon_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
        this, SLOT(RunNextWavelength(int, QProcess::ExitStatus)));
        disconnect(&m_recon_proc, SIGNAL(error(QProcess::ProcessError)),
        this, SLOT(ReconProcessError(QProcess::ProcessError)));
        disconnect(this, SIGNAL(KillRunningJob()),
        &m_recon_proc, SLOT(kill()));
        }
        @

        Excerpted from relevant functions:

        @
        // Check the return code of the previous job, if it came back okay, then we do the next wavelength
        // because the index starts at 0, we increment after the job is started, and then check again
        // the next time we enter this method - if we are outside the length of the list, then we are done
        void CNexusReconJob::RunNextWavelength(int exitCode, QProcess::ExitStatus exitStatus)
        {
        if (((exitCode == 0) || (exitCode == NOISE_FALLBACK)) && (exitStatus == QProcess::NormalExit) && (current_wavelength < wavelengths.length()))
        {
        // state is always one behind the task we want to run

        /* ... remove some non-relevant states ... */
        switch (ReconState)
        {
        case RunPrepocess:
        syslog(LOG_DEBUG, "RunPrepro finished okay");
        ReconState = CleanupPreprocess;
        CleanupPrepro();
        break;
        case RunReconstruction:
        syslog(LOG_DEBUG, "RunRecon finished okay");
        if (exitCode == NOISE_FALLBACK)
        {
        QString user_msg = UserMessageFromExitStatus(exitCode);
        emit ReconError(QString("Recon Warning"), QString("Recon job %1, %2, %3 %4.").arg(m_study, m_specimen, m_exam, user_msg));
        }
        ReconState = CleanupReconstruction;
        CleanupRecon();
        break;

        /* ... remove more non-relevant states ... */

            };
        }
        else if (((exitCode != 0) && (exitCode != NOISE_FALLBACK)) || (exitStatus == QProcess::CrashExit))
        {
            if (!ignore_errors)
            {
                QString user_msg = UserMessageFromExitStatus(exitCode);
                emit ReconError(QString("Recon Error"), QString("Recon job %1, %2, %3 %4.").arg(m_study, m_specimen, m_exam, user_msg));
            }
            emit RunningJobFinished(false);
        }
        else
        {
        

        /* ... */
        }
        }

        // just to show how QProcess is configured and started
        void CNexusReconJob::RunPrepro()
        {
        /* ... /
        m_recon_proc.setNativeArguments(arg);
        m_recon_proc.start(cmd);
        /
        ... */
        }

        void CNexusReconJob::RunRecon()
        {
        /* ... /
        m_recon_proc.setNativeArguments(arg);
        m_recon_proc.start(cmd);
        /
        ... */
        }

        void CNexusReconJob::ReconProcessError(QProcess::ProcessError error)
        {
        syslog(LOG_DEBUG, "Error reported: %d", error);
        if (!ignore_errors)
        {
        QString user_msg = UserMessageFromExitStatus(m_recon_proc.exitCode());
        emit ReconError(QString("Recon Error"), QString("Recon job %1, %2, %3 %4.").arg(m_study, m_specimen, m_exam, user_msg));
        }
        emit RunningJobFinished(false);
        }

        QString CNexusReconJob::UserMessageFromExitStatus(int status)
        {
        QString ret;
        switch (status)
        {
        case FILE_READING_ERROR:
        ret = QString("failed due to an error reading a required input file");
        break;

        /* .... several other options ... */

        };
        
        return ret;
        

        }
        @

        If m_recon_proc (a C console app) calls exit with a negative return value to be mapped to a user message, it goes through ReconProcessError, emits and displays the message on the GUI, and then crashes deleting the object of this class after logging QProcess: Destroyed while process still running ...

        If it calls exit with a non-negative value, everything works just fine.

        1 Reply Last reply
        0
        • M Offline
          M Offline
          MuldeR
          wrote on last edited by
          #4

          Sounds like the process is still running when the QProcess object is destroyed. Maybe your logic somehow starts a new process when the previous one exited with negative code?

          Anyway, as "m_recon_proc" is an auto object, it will be destroyed when your class is destroyed. Therefore I would suggest you put something like this into your destructor, just to be sure:

          @if(m_recon_pro.state() != QProcess::NotRunning)
          {
          if(!QProcess::waitForFinished(10000))
          {
          m_recon_pro.kill();
          m_recon_pro.state.waitForFinished(-1);
          }
          }@

          My OpenSource software at: http://muldersoft.com/

          Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

          Go visit the coop: http://youtu.be/Jay...

          1 Reply Last reply
          0
          • D Offline
            D Offline
            dancingbeartech
            wrote on last edited by
            #5

            I added this code to the dtor:

            @
            syslog(LOG_DEBUG, "m_recon_proc.state(): %d", m_recon_proc.state());
            if (m_recon_proc.state() != QProcess::NotRunning)
            {
            syslog(LOG_DEBUG, "wait for finish");
            if (!m_recon_proc.waitForFinished(10000))
            {
            syslog(LOG_DEBUG, "killing proc");
            m_recon_proc.kill();
            m_recon_proc.waitForFinished(-1);
            }
            }
            else
            {
            syslog(LOG_DEBUG, "apparently we're not running, but we are ??");
            }

            syslog(LOG_DEBUG, "m_recon_proc.state(): %d", m_recon_proc.state());
            

            @

            The syslog output shows that the state is 2, or QProcess::Running.
            It logs "wait for finish", but doesn't wait 10 seconds, it returns immediately and so doesn't call the kill(), logs that the state is still QProcess::Running, and proceeds with the rest of the dtor, and then crashes.

            1 Reply Last reply
            0
            • M Offline
              M Offline
              MuldeR
              wrote on last edited by
              #6

              That doesn't really make sense to me! If QProcess reports the state "Running" and then you call waitForFinished(), it won't return until either the process has terminated or the timeout has been triggered. You can check from the return value of waitForFinished() whether the timeout was triggered or it has terminated. And in case waitForFinished() returned with "true", the state has to be "NoRunning" afterwards.

              Anything else would indicate a bug, I think. What version of Qt you are using?

              --

              You could still try:
              @while(m_recon_proc.state() != QProcess::NotRunning)
              {
              m_recon_proc.kill();
              m_recon_proc.waitForFinished(-1);
              }@

              If that ends up in an infinite loop, something is definitely seriously wrong...

              My OpenSource software at: http://muldersoft.com/

              Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

              Go visit the coop: http://youtu.be/Jay...

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved