Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-blocking pipe using popen?

Tags:

c

linux

pipe

popen

I'd like to open a pipe using popen() and have non-blocking 'read' access to it.

How can I achieve this?

(The examples I found were all blocking/synchronous)

like image 535
jldupont Avatar asked Nov 14 '09 22:11

jldupont


People also ask

Is Popen wait blocking?

Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.

Does Popen need to be closed?

Popen do we need to close the connection or subprocess automatically closes the connection? Usually, the examples in the official documentation are complete. There the connection is not closed. So you do not need to close most probably.

What is pipe in Popen?

The popen() function executes the command specified by the string command. It creates a pipe between the calling program and the executed command, and returns a pointer to a stream that can be used to either read from or write to the pipe.

What is the use of subprocess Popen?

The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.


2 Answers

Setup like this:

FILE *f = popen("./output", "r");
int d = fileno(f);
fcntl(d, F_SETFL, O_NONBLOCK);

Now you can read:

ssize_t r = read(d, buf, count);
if (r == -1 && errno == EAGAIN)
    no data yet
else if (r > 0)
    received data
else
    pipe closed

When you're done, cleanup:

pclose(f);
like image 148
Matt Joiner Avatar answered Oct 01 '22 18:10

Matt Joiner


popen() internally calls pipe(), fork(), dup2() (to point the child process's fds 0/1/2 to the pipes) and execve(). Have you considered using these instead? In that case, you can set the pipe you read to non-blocking using fcntl().

update: Here's an example, just for illustrative purposes:

int read_pipe_for_command(const char **argv)
{
   int p[2];

   /* Create the pipe. */
   if (pipe(p))
   {
      return -1;
   }

   /* Set non-blocking on the readable end. */
   if (fcntl(p[0], F_SETFL, O_NONBLOCK))
   {
      close(p[0]);
      close(p[1]);
      return -1;
   }

   /* Create child process. */
   switch (fork())
   {
      case -1:
          close(p[0]);
          close(p[1]);
          return -1;
      case 0:
          /* We're the child process, close read end of pipe */
          close(p[0]);
          /* Make stdout into writable end */
          dup2(p[1], 1);
          /* Run program */
          execvp(*argv, argv);
          /* If we got this far there was an error... */
          perror(*argv);
          exit(-1);
      default:
          /* We're the parent process, close write end of pipe */
          close(p[1]);
          return p[0];
   }
}
like image 25
asveikau Avatar answered Oct 01 '22 16:10

asveikau