/* * 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. */ /* $Rev$ $Date$ */ #ifndef tuscany_gc_hpp #define tuscany_gc_hpp /** * Garbage collected memory management, using APR memory pools. */ #include #include #include #include #include #include "config.hpp" namespace tuscany { /** * Pointer to a value. */ template class gc_ptr { public: gc_ptr(T* ptr = NULL) throw() : ptr(ptr) { } ~gc_ptr() throw() { } gc_ptr(const gc_ptr& r) throw() : ptr(r.ptr) { } gc_ptr& operator=(const gc_ptr& r) throw() { if(this == &r) return *this; ptr = r.ptr; return *this; } const bool operator==(const gc_ptr& r) const throw() { if (this == &r) return true; return ptr == r.ptr; } const bool operator!=(const gc_ptr& r) const throw() { return !this->operator==(r); } T& operator*() const throw() { return *ptr; } T* operator->() const throw() { return ptr; } operator T*() const throw() { return ptr; } T* ptr; }; /** * Garbage collected APR memory pool. */ class gc_pool { public: gc_pool() : apr_pool(NULL) { } gc_pool(apr_pool_t* p) : apr_pool(p) { } gc_pool(const gc_pool& pool) : apr_pool(pool.apr_pool) { } gc_pool& operator=(const gc_pool& pool) { if (this == &pool) return *this; apr_pool = pool.apr_pool; return *this; } private: friend apr_pool_t* pool(const gc_pool& pool); friend class gc_global_pool_t; friend class gc_scoped_pool; apr_pool_t* apr_pool; }; /** * Return APR pool used by a gc_pool. */ apr_pool_t* pool(const gc_pool& pool) { return pool.apr_pool; } /** * Destroy a memory pool. */ const bool destroy(const gc_pool& p) { apr_pool_destroy(pool(p)); return true; } /** * Initialize APR. */ class gc_apr_context_t { public: gc_apr_context_t() { apr_initialize(); } } gc_apr_context; /** * Maintain a stack of memory pools. */ #ifdef WANT_THREADS __thread #endif apr_pool_t* gc_pool_stack = NULL; /** * Return the current memory pool. */ apr_pool_t* gc_current_pool() { apr_pool_t* apr_pool = gc_pool_stack; if (apr_pool != NULL) return apr_pool; // Create a parent pool for the current thread apr_pool_create(&apr_pool, NULL); assert(apr_pool != NULL); gc_pool_stack = apr_pool; return apr_pool; } /** * Push a pool onto the stack. */ apr_pool_t* gc_push_pool(apr_pool_t* pool) { apr_pool_t* p = gc_pool_stack; gc_pool_stack = pool; return p; } /** * Pop a pool from the stack. */ apr_pool_t* gc_pop_pool(apr_pool_t* pool) { apr_pool_t* p = gc_pool_stack; gc_pool_stack = pool; return p; } /** * A memory pool scope, used to setup a scope in which a particular pool * will be used for all allocations. */ class gc_scoped_pool : public gc_pool { public: gc_scoped_pool() : gc_pool(NULL), prev(gc_current_pool()), owner(true) { apr_pool_create(&apr_pool, NULL); assert(apr_pool != NULL); gc_push_pool(apr_pool); } gc_scoped_pool(apr_pool_t* pool) : gc_pool(pool), prev(gc_current_pool()), owner(false) { gc_push_pool(apr_pool); } ~gc_scoped_pool() { if (owner) apr_pool_destroy(apr_pool); gc_pop_pool(prev); } private: gc_scoped_pool(const unused gc_scoped_pool& pool) : gc_pool(pool.apr_pool), prev(NULL), owner(false) { } apr_pool_t* prev; bool owner; }; /** * Allocates a pointer to an object allocated from a memory pool and * register a cleanup callback for it. */ template apr_status_t gc_pool_cleanup(void* v) { T* t = static_cast(v); t->~T(); return APR_SUCCESS; } template T* gc_new(apr_pool_t* p) { void* gc_new_ptr = apr_palloc(p, sizeof(T)); assert(gc_new_ptr != NULL); apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup, apr_pool_cleanup_null) ; return static_cast(gc_new_ptr); } template T* gc_new(const gc_pool& p) { return gc_new(pool(p)); } template T* gc_new() { return gc_new(gc_current_pool()); } template apr_status_t gc_pool_acleanup(void* v) { int* m = static_cast(v); int n = *m; T* t = (T*)(m + 1); for (int i = 0; i < n; i++, t++) t->~T(); return APR_SUCCESS; } template T* gc_anew(apr_pool_t* p, int n) { int* gc_anew_ptr = static_cast(apr_palloc(p, sizeof(int) + sizeof(T[n]))); assert(gc_anew_ptr != NULL); *gc_anew_ptr = n; apr_pool_cleanup_register(p, gc_anew_ptr, gc_pool_acleanup, apr_pool_cleanup_null) ; return (T*)(gc_anew_ptr + 1); } template T* gc_anew(const gc_pool& p, int n) { return gc_anew(pool(p), n); } template T* gc_anew(int n) { return gc_anew(gc_current_pool(), n); } /** * Allocate an array of chars. */ char* gc_cnew(apr_pool_t* p, int n) { char* gc_cnew_ptr = static_cast(apr_palloc(p, n)); assert(gc_cnew_ptr != NULL); return gc_cnew_ptr; } char* gc_cnew(int n) { return gc_cnew(gc_current_pool(), n); } } #endif /* tuscany_gc_hpp */