You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by David Pope <da...@citrix.com> on 2004/02/03 21:35:17 UTC

thread termination vs. pool lifetime

Hello all,

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

Here's the "obvious" solution (mentioned in December in response to a
similar problem):  Launch the thread in child_init, and register a
cleanup with pchild to terminate the thread.

AFAICS this doesn't really work, due to a combination of the way pool
cleanups work and the way APR threads use pools:

    - A pool's cleanups are run AFTER all of its child pools have been
      destroyed.
    - apr_thread_create() creates a child pool for internal use of
      the thread logic.
    - apr_thread_exit() calls apr_pool_destroy() on this pool.

So the problem is that by the time the cleanup is run, the per-thread
pool has already been destroyed; apr_thread_exit() tries to destroy
it again, and *boom*.

The first question is, did I miss something obvious that could make this
work?

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

Possible solutions:

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

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

    - I don't really need the return value from the thread, so I could
      technically get away with not calling apr_thread_exit().  I don't
      consider this to be a real solution, and probably won't work
      at all for pthreads-based systems.

    - Add a child_shutdown hook to the MPM that is run just before
      pchild is destroyed, which is used instead of the pool cleanup.

The fourth solution is the one I prefer; it has the following advantages:

    - It is symmetrical.  child_init is run immediately after pchild
      is created, so running child_shutdown immediately before its
      destruction makes sense.  It guarantees that the entire pchild
      hierarchy is valid during the hook.  Since pchild was valid
      during child_init, its makes sense for it to be valid during
      child_shutdown.

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

    - It doesn't touch anything else in the system, and is reasonably
      future-proof compared to the first solution; if someone someday
      decides to change the way pconf fits into the system, this part
      of the system won't be affected.

Does this sound like a reasonable solution?

I apologize for the length; this is a complicated problem.

-- Dave
----
David Pope
Citrix Systems, Inc.