2 * ====================================================================
3 * Copyright (c) 2005-2006 CollabNet. All rights reserved.
5 * This software is licensed as described in the file COPYING, which
6 * you should have received as part of this distribution. The terms
7 * are also available at http://subversion.tigris.org/license-1.html.
8 * If newer versions of this license are posted there, you may use a
9 * newer version instead, at your option.
11 * This software consists of voluntary contributions made by many
12 * individuals. For exact contribution history, see the revision
13 * history and logs, available at http://subversion.tigris.org/.
14 * ====================================================================
16 * proxy_apr.swg: This file forms part of the core module (it is %included
17 * only in one place, core.i). It contains Python pool related code.
21 %nodefault apr_array_header_t;
22 %nodefault apr_file_t;
23 %nodefault apr_hash_t;
24 %nodefault apr_pool_t;
26 %opaque_proxy(apr_array_header_t);
27 %opaque_proxy(apr_file_t);
28 %opaque_proxy(apr_hash_t);
31 * SWIG/Python Automatic Memory Management in Subversion: An Overview
32 * ------------------------------------------------------------------
34 * The python memory management code is designed to mark pools as invalid
35 * when their parent pools have been garbage collected. This is implemented
36 * by registering a callback with the Python garbage collector, so that when
37 * the object's parent pool is deleted, we can be notified. For more info on
38 * how these callbacks work, read the Python documentation for the
39 * weakref.ref() function.
41 * Each object has an _is_valid member, and stores a weakref to its parent
42 * pool's _is_valid, and when that weakref is broken _mark_weakpool_invalid()
43 * gets called in order to mark the object as invalid.
45 * You can destroy a pool in three ways:
50 * Each of the above functions destroys the pool's _is_valid member, setting
51 * off a cascade of callback functions that set all the child objects that were
52 * created in the pool to invalid.
54 * If a SWIG object is created from a memory pool, the Python wrapper should
55 * store a full reference to the memory pool and a weakreference to _is_valid.
56 * When you try to access the SWIG object, the Python wrapper will check the
57 * _is_valid weakref to ensure that the pool has not been destroyed (see
58 * proxy.swg to read the implementation details).
60 * This lets us gracefully throw an exception if you try to use an object
61 * that was allocated out of a pool that was cleared, rather than crashing
69 application_pool = None
70 application_pool_lock = threading.Lock()
71 class GenericSWIGWrapper:
72 def __init__(self, this, pool):
73 """Create new Generic SWIG wrapper object"""
76 self._parent_pool = pool
77 self._is_valid = weakref.ref(pool._is_valid)
79 def set_parent_pool(self, pool):
80 """Set the parent pool of this object"""
81 self._parent_pool = pool
84 """Is this object valid?"""
85 return self._is_valid()
87 def assert_valid(self):
88 """Assert that this object is still valid"""
89 assert self.valid(), "This object has already been destroyed"
92 """Return underlying SWIG object"""
96 def _mark_weakpool_invalid(weakpool):
97 if weakpool and weakpool() and hasattr(weakpool(), "_is_valid"):
98 del weakpool()._is_valid
105 def set_parent_pool(self, parent_pool=None):
106 """Create a new memory pool"""
107 global application_pool
110 application_pool_lock.acquire()
112 self._parent_pool = parent_pool or application_pool
115 # Protect important functions from GC
116 self._apr_pool_destroy = _core.apr_pool_destroy
117 self._svn_swig_py_clear_application_pool = \
118 _core.svn_swig_py_clear_application_pool
120 # If we are an application-level pool,
121 # then set this pool to be the application-level pool
122 if not self._parent_pool:
123 svn_swig_py_set_application_pool(self, self)
124 application_pool = self
126 application_pool_lock.release()
129 """Check whether this memory pool and its parents
131 return hasattr(self,"_is_valid")
133 def assert_valid(self):
134 """Assert that this memory_pool is still valid."""
135 assert self.valid(), "This pool has already been destroyed"
138 """Clear embedded memory pool. Invalidate all subpools."""
139 pool = self._parent_pool
141 self.set_parent_pool(pool)
144 """Destroy embedded memory pool. If you do not destroy
145 the memory pool manually, Python will destroy it
147 global application_pool
151 is_application_pool = not self._parent_pool
154 self._apr_pool_destroy(self)
156 # Clear application pool if necessary
157 if is_application_pool:
158 application_pool = None
159 self._svn_swig_py_clear_application_pool()
161 # Mark self as invalid
162 if hasattr(self, "_parent_pool"):
163 del self._parent_pool
164 if hasattr(self, "_is_valid"):
168 """Automatically destroy memory pools, if necessary"""
172 def _mark_valid(self):
173 """Mark pool as valid"""
175 self._weakparent = None
177 if self._parent_pool:
180 # Make sure that the parent object is valid
181 self._parent_pool.assert_valid()
183 # Refer to self using a weakrefrence so that we don't
184 # create a reference cycle
185 weakself = weakref.ref(self)
187 # Set up callbacks to mark pool as invalid when parents
189 self._weakparent = weakref.ref(self._parent_pool._is_valid,
190 lambda x: _mark_weakpool_invalid(weakself))
193 self._is_valid = lambda: 1
195 def _wrap(self, obj):
196 """Mark a SWIG object as owned by this pool"""
198 if hasattr(obj, "set_parent_pool"):
199 obj.set_parent_pool(self)
204 return GenericSWIGWrapper(obj, self)
210 # Initialize a global pool