<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=us-ascii">
<META NAME="Generator" CONTENT="MS Exchange Server version 5.5.2655.35">
<TITLE>thread termination vs. pool lifetime</TITLE>
</HEAD>
<BODY>

<P><FONT SIZE=2>Hello all,</FONT>
</P>

<P><FONT SIZE=2>I'm writing a module that launches a background thread that periodically</FONT>
<BR><FONT SIZE=2>wakes up to do some maintenance work.&nbsp; This thread is launched for the</FONT>
<BR><FONT SIZE=2>child process (all references in this email are to the winnt version</FONT>
<BR><FONT SIZE=2>of the code, but the problem space may be more general).&nbsp; I need to</FONT>
<BR><FONT SIZE=2>gracefully terminate this thread as the child process exits.</FONT>
</P>

<P><FONT SIZE=2>Here's the &quot;obvious&quot; solution (mentioned in December in response to a</FONT>
<BR><FONT SIZE=2>similar problem):&nbsp; Launch the thread in child_init, and register a</FONT>
<BR><FONT SIZE=2>cleanup with pchild to terminate the thread.</FONT>
</P>

<P><FONT SIZE=2>AFAICS this doesn't really work, due to a combination of the way pool</FONT>
<BR><FONT SIZE=2>cleanups work and the way APR threads use pools:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - A pool's cleanups are run AFTER all of its child pools have been</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destroyed.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - apr_thread_create() creates a child pool for internal use of</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the thread logic.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - apr_thread_exit() calls apr_pool_destroy() on this pool.</FONT>
</P>

<P><FONT SIZE=2>So the problem is that by the time the cleanup is run, the per-thread</FONT>
<BR><FONT SIZE=2>pool has already been destroyed; apr_thread_exit() tries to destroy</FONT>
<BR><FONT SIZE=2>it again, and *boom*.</FONT>
</P>

<P><FONT SIZE=2>The first question is, did I miss something obvious that could make this</FONT>
<BR><FONT SIZE=2>work?</FONT>
</P>

<P><FONT SIZE=2>Assuming no:&nbsp; I can see several ways out of this problem, but I'm very</FONT>
<BR><FONT SIZE=2>much the Apache newbie and would appreciate some advice, and perhaps</FONT>
<BR><FONT SIZE=2>some history behind why things were done the way they were.&nbsp; There is</FONT>
<BR><FONT SIZE=2>frequently good reasoning hidden behind hard-to-follow implementation</FONT>
<BR><FONT SIZE=2>details.</FONT>
</P>

<P><FONT SIZE=2>Possible solutions:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - Use apr_pool_parent_get() to get pconf out of pchild, using that</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to launch the thread; but register the termination callback with</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pchild, which guarantees it will run while pconf is still valid.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This solution is awkward and nonintuitive, and not really</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; future-proof.&nbsp; (My familiarity with non-winnt architectures is</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; limited, but I suspect this may not even an option, if pconf</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lives in shared memory or otherwise has out-of-proc limitations.)</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - Modify apr_pool_destroy to run cleanups BEFORE destroying child</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pools.&nbsp; This would pretty much reverse the order of cleanup</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; execution in a pool hierarchy, which is probably a Bad Thing.</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I assume there is a good reason why this order (destroy children</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; before running cleanups) was chosen; can someone provide some</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; background?</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - I don't really need the return value from the thread, so I could</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; technically get away with not calling apr_thread_exit().&nbsp; I don't</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; consider this to be a real solution, and probably won't work</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at all for pthreads-based systems.</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - Add a child_shutdown hook to the MPM that is run just before</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pchild is destroyed, which is used instead of the pool cleanup.</FONT>
</P>

<P><FONT SIZE=2>The fourth solution is the one I prefer; it has the following advantages:</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - It is symmetrical.&nbsp; child_init is run immediately after pchild</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is created, so running child_shutdown immediately before its</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destruction makes sense.&nbsp; It guarantees that the entire pchild</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hierarchy is valid during the hook.&nbsp; Since pchild was valid</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; during child_init, its makes sense for it to be valid during</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; child_shutdown.</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - It removes ordering constraints for cleanups.&nbsp; In my implementation</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I create mutexes in the same pool that I create my thread in</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (seems like a reasonable thing to do, especially if it's pchild).</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If I use a pool cleanup for thread termination, I have to make</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sure my thread termination cleanup is registered LAST, so it's</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executed FIRST.&nbsp; Otherwise, the mutexes my thread uses will be</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gone by the time it tries to acquire them.&nbsp; This pool cleanup</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; approach would be bad because it relies on the internal</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; implementation of the cleanup logic, plus it's nonintuitive.</FONT>
</P>

<P><FONT SIZE=2>&nbsp;&nbsp;&nbsp; - It doesn't touch anything else in the system, and is reasonably</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; future-proof compared to the first solution; if someone someday</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; decides to change the way pconf fits into the system, this part</FONT>
<BR><FONT SIZE=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; of the system won't be affected.</FONT>
</P>

<P><FONT SIZE=2>Does this sound like a reasonable solution?</FONT>
</P>

<P><FONT SIZE=2>I apologize for the length; this is a complicated problem.</FONT>
</P>

<P><FONT SIZE=2>-- Dave</FONT>
<BR><FONT SIZE=2>----</FONT>
<BR><FONT SIZE=2>David Pope</FONT>
<BR><FONT SIZE=2>Citrix Systems, Inc.</FONT>
</P>

</BODY>
</HTML>
