Łukasz Lew
Łukasz Lew

Reputation: 50338

Why this program fails (sometimes)?

#include <cstdio>
#include <QtCore/QProcess>

int main (int argc, char** argv) {
  // if we remove 3 following lines, the problem described below doesn't exists!!
  QProcess process;
  process.start ("asdqwe"); // doesn't matter what we try to execute here.
  process.waitForStarted (1000);

  while (true) {
    char buf[100];
    if (scanf ("%s", buf) == EOF) { // it looks like stdin is closed!
      printf("FAIL\n");
      return 1;
    }
    printf ("%s\n", buf);
  }
  return 0;
}

This code is just a snippet to show the problem. In the full application I need read/write communication with process.

I compile it with:

g++ -o out ./main.cpp -I /usr/include/qt4/ -lQtCore

And execute it from bash command line in terminal.

Why this program sometimes prints FAIL and sometimes will stay in loop?

Edit: This is not question about scan/printf. The same problem is if I use iostreams + string. This question is about interaction of QProcess with file descriptors of parent process.

Upvotes: 2

Views: 697

Answers (2)

Łukasz Lew
Łukasz Lew

Reputation: 50338

#include <cstdio>
#include <QtCore/QProcess>

int main (int argc, char** argv) {
  // if we remove 3 following lines, the problem described below doesn't exists!!
  QProcess process;
  process.start ("asdqwe"); // doesn't matter what we try to execute here.
  process.waitForStarted (1000);

  while (true) {
    char buf[100];
    if (scanf ("%s", buf) == EOF) { // it looks like stdin is closed!
      if (errno == EINTR) {
        errno = 0;
        continue;
      }
      printf("FAIL\n");
      return 1;
    }
    printf ("%s\n", buf);
  }
  return 0;
}

I really use streams, I had to use

cin.clear();
errno = 0;

Upvotes: 0

P Shved
P Shved

Reputation: 99384

Your scanf was interrupted by SIGCHLD signal that was caught when child process terminated. In this case EOF is also returned.

QProcess stuff does set up signal handler for SIGCHLD (check sources): (4.5.3 here)

Q_GLOBAL_STATIC(QProcessManager, processManager)

QProcessManager::QProcessManager()
{
#if defined (QPROCESS_DEBUG)
    qDebug() << "QProcessManager::QProcessManager()";
#endif
    // initialize the dead child pipe and make it non-blocking.
    // (pipe and fcntl skipped - P. Shved.)

    // set up the SIGCHLD handler, which writes a single byte to the dead
    // child pipe every time a child dies.
    struct sigaction oldAction;
    struct sigaction action;
    memset(&action, 0, sizeof(action));
    action.sa_handler = qt_sa_sigchld_handler;
    action.sa_flags = SA_NOCLDSTOP;
    ::sigaction(SIGCHLD, &action, &oldAction);
    if (oldAction.sa_handler != qt_sa_sigchld_handler)
        qt_sa_old_sigchld_handler = oldAction.sa_handler;
}

Upvotes: 3

Related Questions