You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/11/13 00:14:48 UTC

svn commit: r1541303 - /subversion/trunk/subversion/libsvn_subr/object_pool.c

Author: stefan2
Date: Tue Nov 12 23:14:48 2013
New Revision: 1541303

URL: http://svn.apache.org/r1541303
Log:
Fix a pool lifetime issue with object pool container.

The problem is that the owning pool may be the application's
root pool which gets cleaned up *after* other allocators and
their respective root pools.  Since the object pool uses a
separate allocater internally, either pool may receive the
cleanup message first and we must handle both cases.

* subversion/libsvn_subr/object_pool.c
  (svn_object_pool__t): add owning pool
  (root_object_pool_cleanup): new, alternative cleanup function
  (destroy_object_pool): ensure only one cleanup gets executed
  (svn_object_pool__create): update; schedule two alternive cleanups

Modified:
    subversion/trunk/subversion/libsvn_subr/object_pool.c

Modified: subversion/trunk/subversion/libsvn_subr/object_pool.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/object_pool.c?rev=1541303&r1=1541302&r2=1541303&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/object_pool.c (original)
+++ subversion/trunk/subversion/libsvn_subr/object_pool.c Tue Nov 12 23:14:48 2013
@@ -98,6 +98,10 @@ struct svn_object_pool__t
   /* the root pool owning this structure */
   apr_pool_t *root_pool;
 
+  /* this pool determines the minimum lifetime of this container.
+   * We use this to unregister cleanup routines (see below). */
+  apr_pool_t *owning_pool;
+  
   /* allocate the OBJECTS index here */
   apr_pool_t *objects_hash_pool;
 
@@ -127,6 +131,10 @@ destroy_object_pool(svn_object_pool__t *
   return APR_SUCCESS;
 }
 
+/* Forward-declaration */
+static apr_status_t
+root_object_pool_cleanup(void *baton);
+
 /* Pool cleanup function for the whole object pool.  Actual destruction
  * will be deferred until no configurations are left in use.
  */
@@ -135,6 +143,10 @@ object_pool_cleanup(void *baton)
 {
   svn_object_pool__t *object_pool = baton;
 
+  /* disable the alternative cleanup */
+  apr_pool_cleanup_kill(object_pool->root_pool, baton,
+                        root_object_pool_cleanup);
+
   /* from now on, anyone is allowed to destroy the OBJECT_POOL */
   svn_atomic_set(&object_pool->ready_for_cleanup, TRUE);
 
@@ -152,6 +164,23 @@ object_pool_cleanup(void *baton)
   return APR_SUCCESS;
 }
 
+/* This will be called when the root pool gets destroyed before the actual
+ * owner pool.  This may happen if the owner pool is the global root pool. 
+ * In that case, all the relevant cleanup has either already been done or
+ * is default-scheduled.
+ */
+static apr_status_t
+root_object_pool_cleanup(void *baton)
+{
+  svn_object_pool__t *object_pool = baton;
+ 
+  /* disable the full-fledged cleanup code */
+  apr_pool_cleanup_kill(object_pool->owning_pool, baton,
+                        object_pool_cleanup);
+  
+  return APR_SUCCESS;
+}
+
 /* Re-allocate OBJECTS in OBJECT_POOL and remove all unused objects to
  * minimize memory consumption.
  *
@@ -431,6 +460,7 @@ svn_object_pool__create(svn_object_pool_
   SVN_ERR(svn_mutex__init(&result->mutex, thread_safe, root_pool));
 
   result->root_pool = root_pool;
+  result->owning_pool = pool;
   result->objects_hash_pool = svn_pool_create(root_pool);
   result->objects = svn_hash__make(result->objects_hash_pool);
   result->ready_for_cleanup = FALSE;
@@ -440,10 +470,18 @@ svn_object_pool__create(svn_object_pool_
   result->min_unused = min_unused;
   result->max_unused = max_unused;
 
-  /* make sure we clean up nicely */
+  /* make sure we clean up nicely.
+   * We need two cleanup functions of which exactly one will be run
+   * (disabling the respective other as the first step).  If the owning
+   * pool does not cleaned up / destroyed explicitly, it may live longer
+   * than our allocator.  So, we need do act upon cleanup requests from
+   * either side - owning_pool and root_pool.
+   */
   apr_pool_cleanup_register(pool, result, object_pool_cleanup,
                             apr_pool_cleanup_null);
-
+  apr_pool_cleanup_register(root_pool, result, root_object_pool_cleanup,
+                            apr_pool_cleanup_null);
+  
   *object_pool = result;
   return SVN_NO_ERROR;
 }