At 08:02 PM 5/23/2003, Jeff Trawick wrote: >consider code that does something like the following: > >apr_procattr_io_set() >/* we now have 6 pipe handles with no cleanup-for-exec on any */ >apr_proc_create() >/* parent now has 3 of the pipe handles with no cleanup-for-exec on any */ >apr_pool_cleanup_register(parent handle to child's stdin, > child cleanup to close file) >/* now we know that other processes created between now and when we're through >writing to child's stdin won't inherit the handle too and prevent the child >from seeing EOF when this thread closes it */ > >But this entire sequence needs to be in a critical section because any other >code in the process doing an apr_proc_create() at about the same time can >inherit this child's handles and cause problems.
100% correct. I was looking at this a couple of weeks ago, but hadn't formulated any obvious answers to it (without seriously throttling all multithreaded apps.) >I encountered this problem in Apache's mod_ext_filter, which spawns a child >process to filter a response from the server. Banging on the server and >having it spawn sed to filter the response left a number of sed processes >hanging around, all waiting for EOF on stdin. But each sed's stdin pipe was >led open by another sed process, so it mattered not that Apache had closed its >side of the pipe since the pipe was still open. OWWW! That's a case I hadn't considered. However, the right answer is to close the children's side of the pipes, always. If they are left open, it's much harder to detect that the child has died/you've reached EOF. >For mod_ext_filter I can hold a thread mutex around the critical section >above, and that protects it from other instances of mod_ext_filter doing >fork() and inheriting the wrong handle, but it does nothing for other threads >calling apr_proc_create(). The right answer, in part, is to close those child handles. The second side is to protect that window where we declare the handles as keep-open on exec to the point where we've already fork()ed. >It would seem that all of the pipe creation and child cleanup registration >needs to be done inside apr_proc_create() so that it can hold a mutex and all >callers of apr_proc_create() will be happy. I didn't look at it to know if >that would require API changes. I wouldn't be shocked. For the small window between declaring the handles keep-open, fork()ing the child and then closing them in the parent, we absolutely need a mutex to keep things clean. Otherwise, two children may have the write side of the parent's read pipe, and when the first (real) child dies, we don't know it. Bill