* subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
[svn.git] / subversion / bindings / swig / include / proxy_apr.swg
blobbd0fe5b65a4b2710c4c084c79010e15d5e3c3c21
1 /*
2  * ====================================================================
3  * Copyright (c) 2005-2006 CollabNet.  All rights reserved.
4  *
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.
10  *
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  * ====================================================================
15  *
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.
18  */
20 #ifdef SWIGPYTHON
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  * ------------------------------------------------------------------
33  *
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.
40  *
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.
44  *
45  * You can destroy a pool in three ways:
46  *   pool.destroy()
47  *   pool.clear()
48  *   pool.__del__()
49  *
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.
53  *
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).
59  *
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
62  * like we used to do.
63  *
64  */
66 %pythoncode %{
67 import threading
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"""
74     import weakref
75     self.this = this
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
83   def valid(self):
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"
91   def _unwrap(self):
92     """Return underlying SWIG object"""
93     self.assert_valid()
94     return self.this
96 def _mark_weakpool_invalid(weakpool):
97   if weakpool and weakpool() and hasattr(weakpool(), "_is_valid"):
98     del weakpool()._is_valid
102 struct apr_pool_t {
103   %extend {
104     %pythoncode %{
105       def set_parent_pool(self, parent_pool=None):
106         """Create a new memory pool"""
107         global application_pool
109         try:
110           application_pool_lock.acquire()
112           self._parent_pool = parent_pool or application_pool
113           self._mark_valid()
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
125         finally:
126           application_pool_lock.release()
128       def valid(self):
129         """Check whether this memory pool and its parents
130         are still valid"""
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"
137       def clear(self):
138         """Clear embedded memory pool. Invalidate all subpools."""
139         pool = self._parent_pool
140         apr_pool_clear(self)
141         self.set_parent_pool(pool)
143       def destroy(self):
144         """Destroy embedded memory pool. If you do not destroy
145         the memory pool manually, Python will destroy it
146         automatically."""
147         global application_pool
149         self.assert_valid()
151         is_application_pool = not self._parent_pool
153         # Destroy 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"):
165           del self._is_valid
167       def __del__(self):
168         """Automatically destroy memory pools, if necessary"""
169         if self.valid():
170           self.destroy()
172       def _mark_valid(self):
173         """Mark pool as valid"""
175         self._weakparent = None
177         if self._parent_pool:
178           import weakref
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
188           # are destroyed
189           self._weakparent = weakref.ref(self._parent_pool._is_valid,
190             lambda x: _mark_weakpool_invalid(weakself))
192         # Mark pool as valid
193         self._is_valid = lambda: 1
195       def _wrap(self, obj):
196         """Mark a SWIG object as owned by this pool"""
197         self.assert_valid()
198         if hasattr(obj, "set_parent_pool"):
199           obj.set_parent_pool(self)
200           return obj
201         elif obj is None:
202           return None
203         else:
204           return GenericSWIGWrapper(obj, self)
206     %}
207   }
209 %pythoncode %{
210 # Initialize a global pool
211 svn_pool_create()
213 #endif