views:

318

answers:

2
#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.

+3  A: 

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;
}
Pavel Shved
Ah, that seems plausible. Thanks Pavel. But what should I do then?How can I differ SIGCHLD from real EOF? How can it be made cross platform?
Łukasz Lew
You should check `errno == EINTR`. Works on Linux; there are same variables on Windows, but I'm not sure how they work on *that* platform. Or--just use `cin>>s`
Pavel Shved
cin>>s has exactly the same problem.
Łukasz Lew
Interesting... Then check `errno` and read again on `EINTR` -- you have a loop that reads stuff anyway.
Pavel Shved
Now I do that, but it loops and errno is permanently EINTR.
Łukasz Lew
A: 
#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;
Łukasz Lew