/* * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== * * proxy_apr.swg: This file forms part of the core module (it is %included * only in one place, core.i). It contains Python pool related code. */ #ifdef SWIGPYTHON %nodefault apr_array_header_t; %nodefault apr_file_t; %nodefault apr_hash_t; %nodefault apr_pool_t; %opaque_proxy(apr_array_header_t); %opaque_proxy(apr_file_t); %opaque_proxy(apr_hash_t); /* * SWIG/Python Automatic Memory Management in Subversion: An Overview * ------------------------------------------------------------------ * * The python memory management code is designed to mark pools as invalid * when their parent pools have been garbage collected. This is implemented * by registering a callback with the Python garbage collector, so that when * the object's parent pool is deleted, we can be notified. For more info on * how these callbacks work, read the Python documentation for the * weakref.ref() function. * * Each object has an _is_valid member, and stores a weakref to its parent * pool's _is_valid, and when that weakref is broken _mark_weakpool_invalid() * gets called in order to mark the object as invalid. * * You can destroy a pool in three ways: * pool.destroy() * pool.clear() * pool.__del__() * * Each of the above functions destroys the pool's _is_valid member, setting * off a cascade of callback functions that set all the child objects that were * created in the pool to invalid. * * If a SWIG object is created from a memory pool, the Python wrapper should * store a full reference to the memory pool and a weakreference to _is_valid. * When you try to access the SWIG object, the Python wrapper will check the * _is_valid weakref to ensure that the pool has not been destroyed (see * proxy.swg to read the implementation details). * * This lets us gracefully throw an exception if you try to use an object * that was allocated out of a pool that was cleared, rather than crashing * like we used to do. * */ %pythoncode %{ import threading application_pool = None application_pool_lock = threading.Lock() class GenericSWIGWrapper: def __init__(self, this, pool): """Create new Generic SWIG wrapper object""" import weakref self.this = this self._parent_pool = pool self._is_valid = weakref.ref(pool._is_valid) def set_parent_pool(self, pool): """Set the parent pool of this object""" self._parent_pool = pool self._is_valid = weakref.ref(pool._is_valid) def valid(self): """Is this object valid?""" return self._is_valid() def assert_valid(self): """Assert that this object is still valid""" assert self.valid(), "This object has already been destroyed" def _unwrap(self): """Return underlying SWIG object""" self.assert_valid() return self.this def _mark_weakpool_invalid(weakpool): if weakpool: pool = weakpool() if pool: try: del pool._is_valid except AttributeError: pass %} struct apr_pool_t { %extend { %pythoncode %{ def set_parent_pool(self, parent_pool=None): """Create a new memory pool""" global application_pool try: application_pool_lock.acquire() self._parent_pool = parent_pool or application_pool self._mark_valid() # Protect important functions from GC self._apr_pool_destroy = _core.apr_pool_destroy self._svn_swig_py_clear_application_pool = \ _core.svn_swig_py_clear_application_pool # If we are an application-level pool, # then set this pool to be the application-level pool if not self._parent_pool: svn_swig_py_set_application_pool(self, self) application_pool = self finally: application_pool_lock.release() def valid(self): """Check whether this memory pool and its parents are still valid""" try: self._is_valid except AttributeError: return False # We must check whether the parent pool is valid even if # the pool is valid because weakref's callback is not # invoked when it is finalized by cyclic garbage collector if self._parent_pool: return self._parent_pool.valid() else: return True def assert_valid(self): """Assert that this memory_pool is still valid.""" assert self.valid(), "This pool has already been destroyed" def clear(self): """Clear embedded memory pool. Invalidate all subpools.""" pool = self._parent_pool apr_pool_clear(self) self.set_parent_pool(pool) def destroy(self): """Destroy embedded memory pool. If you do not destroy the memory pool manually, Python will destroy it automatically.""" global application_pool self.assert_valid() is_application_pool = not self._parent_pool # Destroy pool self._apr_pool_destroy(self) # Clear application pool if necessary if is_application_pool: application_pool = None self._svn_swig_py_clear_application_pool() # Mark self as invalid try: del self._parent_pool except AttributeError: pass try: del self._is_valid except AttributeError: pass def __del__(self): """Automatically destroy memory pools, if necessary""" if self.valid(): self.destroy() def _mark_valid(self): """Mark pool as valid""" self._weakparent = None if self._parent_pool: import weakref # Make sure that the parent object is valid self._parent_pool.assert_valid() # Refer to self using a weakreference so that we don't # create a reference cycle weakself = weakref.ref(self) # Set up callbacks to mark pool as invalid when parents # are destroyed self._weakparent = weakref.ref(self._parent_pool._is_valid, lambda x: _mark_weakpool_invalid(weakself)) # Mark pool as valid self._is_valid = lambda: 1 def _wrap(self, obj): """Mark a SWIG object as owned by this pool""" self.assert_valid() fn = getattr(obj, 'set_parent_pool', None) if fn is not None: fn(self) return obj elif obj is None: return None else: return GenericSWIGWrapper(obj, self) %} } }; %pythoncode %{ # Initialize a global pool svn_pool_create() %} #endif