General
cancel
Showing results for 
Search instead for 
Did you mean: 

Are popen/pclose function thread-safe?

Krishna R
Advisor

Are popen/pclose function thread-safe?

Hi folks,

I would like to know if popen/pclose functions are thread-safe or not. I googled a bit, but couldn't find a conclusive answer anywhere.

We have a multi-threaded application where potentially many threads can call popen/pclose, fork/exec parallelly (we don't use any mutex to serialize the calls).

Would appreciate any help in pointers to the following question:
1. Is popen/pclose thread-safe?
2. Even if they are thread-safe, are popen and fork thread-safe together?

If interested, please check the nature of the issue i'm facing:

We recently ran into issues (on Linux 2.6.16) very rarely with a thread blocked in pclose forever. strace shows it is blocked on 'wait' call for the child pid.

We inspected the child process --> it is trying to read from stdin (strace shows read(0...).

I ran strace on a sample program to understand the behavior and found that the parent calls close(pipe-fd) first and then goes to wait. If close was called successfully, the child program would have gotten the EOF and exited.

Our current suspicion is on MT-usage of popen/pclose/fork since the application spawns a number of child processes (that might have possibly gone into this state).

I'd also appreciate if any help where I can find source code in glibc for popen/pclose.


Thanks,
Krishna R
7 REPLIES
Dennis Handly
Acclaimed Contributor

Re: Are popen/pclose function thread-safe?

The problem with popen is that it implies fork. And the problem with fork is that you must have atfork handlers to release all of your held mutexes when you start your child process.

Unless you can be sure you don't execute any paths that check mutexes, before you exec.

On HP-UX, system(3) is documented as not thread safe but popen(3) isn't listed.
Krishna R
Advisor

Re: Are popen/pclose function thread-safe?

Thanks for the reply!

I think I understand the implication with fork and mutexes (either ours or from the OS such as loader's, malloc's etc.).

In our case, we dont see any threads blocked/deadlocked in any mutexes, as all threads are processing normally, only that one thread is blocked in wait().

Even after this situation, other threads are still forking/popening. I was wondering if popen/pclose uses any global/static data that might have ended in a race condition when 2 threads are calling the api.

I checked glibc code for popen but didn't find any.
Dennis Handly
Acclaimed Contributor

Re: Are popen/pclose function thread-safe?

>only that one thread is blocked in wait().

If you are doing multiple pcloses or forks, the wait(2) calls can get confused.
Goran Koruga
Honored Contributor

Re: Are popen/pclose function thread-safe?

It's probably waiting for your child to finish, but your child is waiting for input - try adding a timeout there or investigate why it's not getting input.

It's normal to close one side of the pipe in parent, while in the child one uses dup() to open (reassign really) stdin, stdout and stderr and then you can close original FD-s.

Hope this helps,
Goran
Krishna R
Advisor

Re: Are popen/pclose function thread-safe?

@Dennis,

Thanks. I too think that's what is happening. The solution is to serialize the forks/waits between the threads using a mutex, I believe.

Krishna R
Advisor

Re: Are popen/pclose function thread-safe?

@Goran,

Thanks for your response.

I did try to inspect the child process (in our case its actually the rmail/sendmail linux command), and the process is waiting to read on stdin (strace showed read(0,...) as I mentioned before)

We use popen to fork the process with "w" option, so a pipe is created with write-end for our process and write-end to the process. The parent must have closed the write-end and doing a wait() (when pclose is called), which means the child must have read an EOF. There

We could not find any reason for this, unless multiple threads causing popen/fork etc. led to a mixup of fd's and child pids...



Krishna R
Advisor

Re: Are popen/pclose function thread-safe?

Also, incase of popen/pclose, the dup() and close() of fd is taken care automatically and hence I believe they should be handled fine (unless there's a bug ofc).

I checked iopopen.c in glibc (am not a linux hacker - this is my first time with GNU code :)) and they handle the dup and close based on the mode (r/w) as expected:

((_IO_proc_file *) fp)->pid = child_pid = _IO_fork ();
if (child_pid == 0)
{
int child_std_end = mode[0] == 'r' ? 1 : 0;
struct _IO_proc_file *p;

_IO_close (parent_end);
if (child_end != child_std_end)
{
_IO_dup2 (child_end, child_std_end);
_IO_close (child_end);
}
/* POSIX.2: "popen() shall ensure that any streams from previous
popen() calls that remain open in the parent process are closed
in the new child process." */
for (p = proc_file_chain; p; p = p->next)
_IO_close (_IO_fileno ((_IO_FILE *) p));

_IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0);
_IO__exit (127);
}
_IO_close (child_end);