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)
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)
Have you looked at the "see also" section of the man page for popen()?
Quick google search revealed this page: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#blocking Talks about blocking and non-blocking access to file descriptors.
Never tried it but I don't see why you couldn't grab the file descriptors with fileno(), use fcntl() to set to non-blocking, and use read()/write(). Worth a try.
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 parent process, close the writable part of the pipe */
close(p[1]);
return p[0];
default:
/* Close readable 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);
}
}
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);