0

How can a C-client started by popen and writing to stdout properly detect that the calling process has called pclose.

I am sending binary data from a small client program written in C to Matlab. To this end, Matlab is starting the process by calling popen inside an API written in C. The client is continuously writing binary data to stdout using fwrite. When Matlab is stopping, the API apparently calls pclose on the client's handle, but that does not stop the client process. I guess the fwrite will not raise an error, as the data gets buffered by the OS. So what is the appropriate way to detect the pclose inside the client?

BTW I will run into the same problem agin, when trying to write to some C-client from within Matlab.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    The calling process closes the pipe and then waits for the c-client to terminate. The c-client can try to write and look for SIGPIPE signals, or ignore SIGPIPE and spot the write error. It's not clear there are other ways to find out. – Jonathan Leffler Jul 25 '19 at 16:14
  • 1
    If your client process is not receiving a SIGPIPE (which I suppose is what you mean by "fwrite ... rais[ing] an error"), then there is very likely a file descriptor left open somewhere. – William Pursell Jul 25 '19 at 16:53
  • The data doesn't get buffered by the OS, but by the stdio part of the C library. You should either make the stdout unbuffered with `setvbuf()` or flush it after each `fwrite()` with `fflush(stdout)` -- and **not ignore** the return value of either `fwrite` or `fflush`. If there's any data buffered by `fwrite()`, `printf()`, puts(), etc `fflush(stdout)` should end up calling the `write()` syscall, and a write to pipe with no reader will either trigger a `SIGPIPE` or fail with errno set to `EPIPE` (the latter in the case where someone has foolishly set the `SIGPIPE` disposition to "ignore"). –  Jul 25 '19 at 17:21
  • @WilliamPursell ... or any of the parents of the process has set the `SIGPIPE` disposition to "ignore", which is inherited through forks and execs. –  Jul 25 '19 at 17:25
  • You can also consider implementing your own alternative to `popen`, where you kill the client process after you are done. See: https://stackoverflow.com/questions/6743771/popen-alternative – jxh Jul 25 '19 at 18:34

1 Answers1

0

Three ways:

  1. If you are reading from the pipe, and the other end goes away, you should get end-of-file, and you can detect that, and stop.
  2. If you are reading from the pipe, and you control the protocol, the other end can send you a "quit" command over the pipe, and you can read that, and stop.
  3. If you are writing to the pipe, and the other end goes away, you should get a SIGPIPE signal, which by default should kill your process.

Note that #1 only works if the other end is the only process that has the pipe open. If any other process has the writing end of pipe open, you won't get EOF, and you won't know to stop. If you're calling pipe(), then exec(), it's easy for you to have the writing end of the pipe open. This is a common mistake. (Since you're calling popen(), though, it's less likely you're having this problem.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • The two read options are 'not applicable' to the question where the process is writing — but they are a part of the general answer. A fourth option is that the writing process ignores SIGPIPE, whereupon the write will fail with an error (EINTR?) rather than generating an ignored signal. – Jonathan Leffler Jul 25 '19 at 16:15
  • O.k. 3. seems to be the solution for me. How would I check for SIGPIPE signal? – wolfgang6444 Jul 25 '19 at 16:20
  • @wolfgang6444 Unless you're doing something special, you shouldn't have to do anything -- by default SIGPIPE will kill your process. Only if you (or someone on your behalf) has caught or ignored SIGPIPE will you have to do something so that you can explicitly catch or unignore it. – Steve Summit Jul 25 '19 at 16:22
  • O.K. - so I have to check if the API is really calling pclose on the client. – wolfgang6444 Jul 25 '19 at 16:25