Overview
Features
Download
Documentation
Community
Add-Ons & Services

Multiple processes (Reusing pipes issue?)

Please post support and help requests here.

Multiple processes (Reusing pipes issue?)

Postby mattcox » 09 May 2012, 14:52

Hi.

I've been experimenting with processes and pipes. But I am having some issues when relaunching a process after it has been killed. The process launches ok, but I am having trouble accessing any data in the pipes. I assume this is because I have already assigned them to another process and they can't be reassigned?

Basically I am coding a simple testing app that will run through a series of predefined commands, and then in turn, launch different versions of a command line application and monitor the results (look for crashes, command firing times...etc). Here is my basic code:

Defined inside my launchProcess class header file.
Code: Select all
Poco::Pipe      outPipe;
Poco::Pipe      inPipe;
Process::PID    processID;


Code: Select all
int launchProcess::launchApp_launch(string appPath)
{
   // Launches an instance of app.
   // Should return 1 if it failed and 0 if it is successful.

   // Check that the application exists and is readable.
   ifstream fileStream;
   fileStream.open (appPath, ios::in);
   if (!fileStream.is_open()) {
      return 1;
   }
   fileStream.close();

   // Launch application.
   vector<string> args;
   ProcessHandle ph = Process::launch(appPath, args, &inPipe, &outPipe, &outPipe);

   // Get the process ID. We will use this later on to quit the application.
   processID = ph.id();

   return 0;
}


The app I am reading will either return a feedback line (such as "+ Command Successful\n") or a command prompt (Which is always ">").
Code: Select all
int launchProcess::launchApp_read(string& output, double timeout)
{
   // This will read the contents of the child's STDOUT pipe.
   // Should return 1 if it failed and 0 if it is successful.

   Poco::PipeInputStream istr(outPipe);

   if(istr.good() == false) {
      istr.clear();
      return 1;
   } else {
      // Manually get the data, either until a "\n" is reached, or until a ">" is reached.
      int c = istr.get();
      output = "";
      if(c == -1){
         istr.clear();
         return 1;
      }
      while (c != -1 && c != '\n' && c != '>') {
         output += (char) c;
         c = istr.get();
      }
      if(c == '\n') {
         output = output + "\n";
      } else if(c == '>') {
         output = "> ";
      }
      istr.clear();
      return 0;
   }
}


Code: Select all
int launchProcess::launchApp_write(string input)
{
   // This will write the content of the input variable to the Child's STDIN.
   // Should return 1 if it failed and 0 if it is successful.

   // Set the output stream.
   Poco::PipeOutputStream ostr(inPipe);

   // Check if the output stream is valid.
   if(ostr.good() == false) {
      return 1;
   } else {
      // Attempt to write to the output stream.
      input = input + "\n";
      const char * inputChar = input.c_str();
      int inputCharLen = input.length();
      ostr.write(inputChar, inputCharLen);
      return 0;
   }
}


Code: Select all
int launchProcess::launchApp_close()
{
   // This will quit the application.
   // Should return 1 if it failed and 0 if it is successful.

   // Set the input and output streams.
   Poco::PipeOutputStream ostr(inPipe);
   Poco::PipeInputStream istr(outPipe);

   // Check if the output stream is valid.
   if(ostr.good() == false) {
      // Kill application anyway.
      Process::kill(processID);
      return 1;
   } else {
      // Send the app.close command.
      ostr.write("app.close\n", 10);
      printf("app.close\n");
      // Kill app as well...just incase something failed with the app.close command.
      Process::kill(processID);
      return 0;
   }
}


I then have a block of code in my main() function that reads two text files; an application text file and a test text file. For every line in the application text file, it launches the app by running launchApp_launch() and then for every line in the test text file it fires of the test commands and reads the output, using launchApp_write() and launchApp_read(). When it gets to the end of the test text file, it runs launchApp_close() and then the loop starts again with the next application path in the app text file. It continues like this until the application text file reaches eof.

So it's something like this:
(I've removed a lot of the code that wasn't relevant - like getting the app file and test file).
Code: Select all
void main() {
   int appFile_eof = 0;
   int testFile_eof = 0;
   string pathToApp;
   string testLine;
   string readOutput;
   while (appFile_eof != 1) {
      appFile_eof = getPathToApp(pathToApp); // Reads the path from the app text file.
      launchProcess.launchApp_launch(pathToApp);// Launch the application.
      while (testFile_eof != 1) {
         testFile_eof = getLineOfTest(testLine); // Reads a line from the test text file.
         launchProcess.launchApp_write(testLine); // Writes a line from the test text file.
         launchProcess.launchApp_read(readOutput); // Reads the response from the process.
      }
      launchProcess.close(); // Quit the application.
   }
   // We do something with the response, check for crashes...etc.
   cout << "Testing Complete" << endl;
}


So as you can see (If you've made it this far), the code will run through each line in the application file and also each line in the test text file. So the commands listed inside of the test text file will be fired on every version of the app listed in the application text file.

This code works fine if I am just testing one application. So if my application text file has just the one line, it launches the app, runs the commands in the test text file and quits. However, if I have more than one line/path in my application text file, it will work for the first application/line, but when it reaches the second, it'll launch the app but fail when it tries to read from the pipe. It's failing because there is no data in the pipe - I assume this is because the pipe is still assigned to the previous process that has been killed?

I had assumed that if I killed a process, it would release the pipe. But I guess not.

Does anyone have any idea how I can reassign a pipe? Or is that even the issue here?

Thanks.
-Matt
mattcox
 
Posts: 7
Joined: 08 May 2012, 21:46

Re: Multiple processes (Reusing pipes issue?)

Postby mattcox » 09 May 2012, 21:35

Solved my issue. Instead of declaring the inPipe and outPipe variables in the class declaration and using that throughout. I created a local outPipe and inPipe in the launchApp function and set the variables defined in the class declaration to those temp variables.

It works fine now.Surprised it didn't occur to me straight away.

-Matt
mattcox
 
Posts: 7
Joined: 08 May 2012, 21:46


Return to Support

Who is online

Users browsing this forum: cB32Dg3H2TTm and 2 guests