Michael
Michael

Reputation: 9402

waiting for popen subprocess to terminate before reading

How can I tell when the process started by popen is done?

I'm passing the descriptor (from fileno() called on the FILE * returned by popen) to a function which calls fstat() and uses the value to returned to determine how much to read. Surprisingly this actually works if there is a delay (for instance, stepping through the debugger) but returns a file size of zero if called immediately after the popen. So I need some way to wait until all the output is ready - how can I do this? I assume I can't call pclose() even though it does this waiting, because then the descriptor isn't valid any more.

Update: Actually, it appears the code works fine if I pretend the fstat() failed on the pipe call - the issue seems to be that fstat() does not fail, as expected. So what I really want is a way to tell if the descriptor is a pipe - fstat returns st_mode=0 (was expecting S_IFIFO!)

Upvotes: 1

Views: 1829

Answers (5)

Alan Corey
Alan Corey

Reputation: 611

I don't know if this will help but it's a similar situation where I want to store the output of a popen().

void live(void) { // scan and read the dongle
  FILE *dong;  // dongle
  char *c;
  char cmd[] = "rtl_power -f 88M:108M:5k -1 -";
  c = buf;  // externally allocated buffer
  dong = popen(cmd,"r");
  while (!feof(dong)) {
    *c = fgetc(dong);
    c++;
  }
  pclose(dong);
  textsize = (int) (c-buf);
  printf("Read %i bytes\n",textsize);
}

It sort of tails the file, copying it to buf[]. It's been working for a few days, I've even published the program on Sourceforge. Running Linux, Debian and Raspbian.

Upvotes: 0

Ken Thomases
Ken Thomases

Reputation: 90571

If you don't read from the pipe, the subprocess is fairly likely to never terminate. The buffer between the ends of the pipe is fairly small. So, as the subprocess writes output, the buffer will fill and the subprocess will block in the write() call. Then you'll have deadlock. The parent process is waiting for the subprocess to terminate before reading from the pipe, the subprocess is blocked until the parent process reads from the pipe and so can't terminate.

Upvotes: 3

This won't work (at least not on Linux system).

The file descriptor (as given by fileno(3)) of a popen(3)-ed command is a pipe(7). So it is not seekable, and fstat(2) won't give any significant size on it.

If you need such fine grained information, don't use popen but call the underlying syscalls pipe(2), fork(2), execve(2), waitpid(2) then you can use poll(2).

If you insist on using popen you could still poll its fileno; however there is no standard way to get its pid (to use waitpid) this is why you should use the syscalls(2) directly.

I guess that fstat-ing a pipe should not give a plain file but a fifo(7) if it succeeds, so special-case on st.st_mode & S_IFMT == S_IFIFO to detect that case.

Upvotes: 2

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215277

Perhaps you have some special reason for wanting to determine the amount of data available on the pipe from popen, but this is not generally available and not the intended usage case. popen (in read mode) is intended to be used with programs that output a stream of data as fast as they can (note: they'll block on the pipe when its buffer fills up if you don't read it instantly) and then exit once they're done, producing EOF for your reader. This gives you pretty much flexibility; you can use line-based read functions like fgets or getline, read the while stream until EOF, or read large chunks with fread and be prepared for a short read on the last one.

Upvotes: 1

user3159253
user3159253

Reputation: 17455

In unix-like OSes a parent process recieves SIGCHLD when its children terminate. See this tutorial

Also you can select() on the pipe descriptor to check if there's a data to read. When the pipe is closed a "read-ready" event with zero-size data is generated.

Upvotes: 1

Related Questions