summaryrefslogtreecommitdiffstats
path: root/sca-cpp/branches/lightweight-sca/kernel/gc.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/branches/lightweight-sca/kernel/gc.hpp')
-rw-r--r--sca-cpp/branches/lightweight-sca/kernel/gc.hpp500
1 files changed, 500 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/kernel/gc.hpp b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp
new file mode 100644
index 0000000000..32ad8160cc
--- /dev/null
+++ b/sca-cpp/branches/lightweight-sca/kernel/gc.hpp
@@ -0,0 +1,500 @@
+/*
+ * 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 "config.hpp"
+#ifdef WANT_MALLOC_MMAP
+#include <sys/mman.h>
+#include <malloc.h>
+#endif
+#include <stdlib.h>
+#include <apr_general.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+#include <assert.h>
+#include <new>
+#ifdef WANT_THREADS
+#include <pthread.h>
+#endif
+
+namespace tuscany
+{
+
+#ifdef WANT_MAINTAINER_ASSERT
+
+/**
+ * Force a core dump on assertion violation.
+ */
+bool assertOrFail(const bool expr) {
+ if (!expr)
+ abort();
+ return true;
+}
+
+#else
+
+#define assertOrFail(expr)
+
+#endif
+
+/**
+ * Pointer to a value.
+ */
+template<typename T> 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==(T* p) const throw() {
+ return ptr == p;
+ }
+
+ const bool operator!=(const gc_ptr& r) const throw() {
+ return !this->operator==(r);
+ }
+
+ const bool operator!=(T* p) const throw() {
+ return !this->operator==(p);
+ }
+
+ T& operator*() const throw() {
+ return *ptr;
+ }
+
+ T* operator->() const throw() {
+ return ptr;
+ }
+
+ operator T*() const throw() {
+ return ptr;
+ }
+
+ T* ptr;
+};
+
+/**
+ * Initialize APR.
+ */
+class gc_apr_context_t {
+public:
+ gc_apr_context_t() {
+ apr_initialize();
+ }
+} gc_apr_context;
+
+/**
+ * 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_child_pool;
+ friend class gc_local_pool;
+ friend class gc_scoped_pool;
+
+ apr_pool_t* apr_pool;
+};
+
+/**
+ * Return the APR pool used by a gc_pool.
+ */
+apr_pool_t* pool(const gc_pool& pool) {
+ return pool.apr_pool;
+}
+
+/**
+ * Maintain a stack of memory pools.
+ */
+#ifdef WANT_THREADS
+
+class gc_pool_stack_t {
+public:
+ gc_pool_stack_t() {
+ int rc = pthread_key_create(&key, NULL);
+ assertOrFail(rc == 0);
+ }
+
+ operator apr_pool_t*() const {
+ return static_cast<apr_pool_t*>(pthread_getspecific(key));
+ }
+
+ const gc_pool_stack_t& operator=(apr_pool_t* p) {
+ pthread_setspecific(key, p);
+ return *this;
+ }
+
+private:
+ pthread_key_t key;
+} gc_pool_stack;
+
+#else
+apr_pool_t* gc_pool_stack = NULL;
+#endif
+
+/**
+ * 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;
+}
+
+/**
+ * Return the current memory pool.
+ */
+apr_pool_t* gc_current_pool() {
+ apr_pool_t* p = gc_pool_stack;
+ if (p != NULL)
+ return p;
+
+ // Create a parent pool for the current thread
+ apr_pool_create(&p, NULL);
+ assertOrFail(p != NULL);
+ gc_push_pool(p);
+ return p;
+}
+
+/**
+ * A child memory pool, which will be destroyed when its parent pool is destroyed.
+ */
+class gc_child_pool : public gc_pool {
+public:
+
+ gc_child_pool() : gc_pool(NULL), owner(true) {
+ apr_pool_create(&apr_pool, gc_current_pool());
+ assertOrFail(apr_pool != NULL);
+ }
+
+ gc_child_pool(const gc_child_pool& p) : gc_pool(p.apr_pool), owner(false) {
+ }
+
+ const gc_child_pool& operator=(const gc_child_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ owner = false;
+ return *this;
+ }
+
+
+private:
+ bool owner;
+};
+
+/**
+ * A local pool scope, which will be destroyed when exiting the current scope.
+ */
+class gc_local_pool : public gc_pool {
+public:
+
+ gc_local_pool() : gc_pool(NULL), owner(true) {
+ apr_pool_create(&apr_pool, gc_current_pool());
+ assertOrFail(apr_pool != NULL);
+ }
+
+ ~gc_local_pool() {
+ if (owner)
+ apr_pool_destroy(apr_pool);
+ }
+
+ gc_local_pool(const gc_local_pool& p) : gc_pool(p.apr_pool), owner(false) {
+ }
+
+ const gc_local_pool& operator=(const gc_local_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ owner = false;
+ return *this;
+ }
+
+private:
+ bool owner;
+};
+
+/**
+ * A memory pool scope, used to setup a scope in which a particular pool will be
+ * used for all allocations. Will be destroyed when existing the current scope.
+ */
+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, prev);
+ assertOrFail(apr_pool != NULL);
+ gc_push_pool(apr_pool);
+ }
+
+ gc_scoped_pool(apr_pool_t* p) : gc_pool(p), 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);
+ }
+
+ gc_scoped_pool(const gc_scoped_pool& p) : gc_pool(p.apr_pool), prev(p.prev), owner(false) {
+ }
+
+ const gc_scoped_pool& operator=(const gc_scoped_pool& p) {
+ if(this == &p)
+ return *this;
+ apr_pool = p.apr_pool;
+ prev = p.prev;
+ owner = false;
+ return *this;
+ }
+
+private:
+ 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<typename T> apr_status_t gc_pool_cleanup(void* v) {
+ T* t = (T*)v;
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_new(apr_pool_t* p) {
+ void* gc_new_ptr = apr_palloc(p, sizeof(T));
+ assertOrFail(gc_new_ptr != NULL);
+ apr_pool_cleanup_register(p, gc_new_ptr, gc_pool_cleanup<T>, apr_pool_cleanup_null) ;
+ return (T*)(gc_new_ptr);
+}
+
+template<typename T> T* gc_new(const gc_pool& p) {
+ return gc_new<T>(pool(p));
+}
+
+template<typename T> T* gc_new() {
+ return gc_new<T>(gc_current_pool());
+}
+
+template<typename T> apr_status_t gc_pool_acleanup(void* v) {
+ size_t* m = static_cast<size_t*>(v);
+ size_t n = *m;
+ T* t = (T*)(m + 1);
+ for (size_t i = 0; i < n; i++, t++)
+ t->~T();
+ return APR_SUCCESS;
+}
+
+template<typename T> T* gc_anew(apr_pool_t* p, size_t n) {
+ size_t* gc_anew_ptr = static_cast<size_t*>(apr_palloc(p, sizeof(size_t) + sizeof(T) * n));
+ assertOrFail(gc_anew_ptr != NULL);
+ *gc_anew_ptr = n;
+ apr_pool_cleanup_register(p, gc_anew_ptr, gc_pool_acleanup<T>, apr_pool_cleanup_null) ;
+ return (T*)(gc_anew_ptr + 1);
+}
+
+template<typename T> T* gc_anew(const gc_pool& p, size_t n) {
+ return gc_anew<T>(pool(p), n);
+}
+
+template<typename T> T* gc_anew(size_t n) {
+ return gc_anew<T>(gc_current_pool(), n);
+}
+
+/**
+ * Allocate an array of chars.
+ */
+char* gc_cnew(apr_pool_t* p, size_t n) {
+ char* gc_cnew_ptr = static_cast<char*>(apr_palloc(p, n));
+ assertOrFail(gc_cnew_ptr != NULL);
+ return gc_cnew_ptr;
+}
+
+char* gc_cnew(size_t n) {
+ return gc_cnew(gc_current_pool(), n);
+}
+
+/**
+ * Pool based equivalent of the standard malloc function.
+ */
+void* gc_pool_malloc(size_t n) {
+ size_t* ptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+ assertOrFail(ptr != NULL);
+ *ptr = n;
+ return ptr + 1;
+}
+
+/**
+ * Pool based equivalent of the standard realloc function.
+ */
+void* gc_pool_realloc(void* ptr, size_t n) {
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ size_t* rptr = static_cast<size_t*>(apr_palloc(gc_current_pool(), sizeof(size_t) + n));
+ assertOrFail(rptr != NULL);
+ *rptr = n;
+ memcpy(rptr + 1, ptr, size < n? size : n);
+ return rptr + 1;
+}
+
+/**
+ * Pool based equivalent of the standard free function.
+ */
+void gc_pool_free(unused void* ptr) {
+ // Memory allocated from a pool is freed when the pool is freed
+}
+
+/**
+ * Pool based equivalent of the standard strdup function.
+ */
+char* gc_pool_strdup(const char* str) {
+ char* dptr = static_cast<char*>(gc_pool_malloc(strlen(str) + 1));
+ assertOrFail(dptr != NULL);
+ strcpy(dptr, str);
+ return dptr;
+}
+
+#ifdef WANT_MALLOC_MMAP
+
+/**
+ * Mmap based memory allocation functions.
+ */
+
+/**
+ * Mmap based equivalent of the standard malloc function.
+ */
+void* gc_mmap_malloc(size_t n, unused const void* caller) {
+ //printf("gc_mmap_malloc %d", n);
+ size_t* ptr = static_cast<size_t*>(mmap(NULL, sizeof(size_t) + n, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
+ assertOrFail(ptr != NULL);
+ *ptr = n;
+ //printf(" %p\n", ptr + 1);
+ return ptr + 1;
+}
+
+/**
+ * Mmap based equivalent of the standard realloc function.
+ */
+void* gc_mmap_realloc(void* ptr, size_t n, const void* caller) {
+ if (ptr == NULL)
+ return gc_mmap_malloc(n, caller);;
+ //printf("gc_mmap_realloc %p %d", ptr, n);
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ size_t* rptr = static_cast<size_t*>(mremap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size, sizeof(size_t) + n, MREMAP_MAYMOVE, NULL));
+ assertOrFail(rptr != NULL);
+ *rptr = n;
+ //printf(" %p\n", rptr + 1);
+ return rptr + 1;
+}
+
+/**
+ * Mmap based equivalent of the standard free function.
+ */
+void gc_mmap_free(void* ptr, unused const void* caller) {
+ //printf("gc_mmap_free %p\n", ptr);
+ if (ptr == NULL)
+ return;
+ size_t size = *(static_cast<size_t*>(ptr) - 1);
+ munmap(static_cast<size_t*>(ptr) - 1, sizeof(size_t) + size);
+}
+
+/**
+ * Mmap based equivalent of the standard memalign function.
+ */
+void* gc_mmap_memalign(unused size_t alignment, size_t n, unused const void* caller) {
+ //printf("gc_mmap_memalign %d %d\n", alignment, n);
+ return gc_mmap_malloc(n, caller);
+}
+
+/**
+ * Install the mmap based memory allocation functions.
+ */
+void gc_mmap_init_hook(void) {
+ __malloc_hook = gc_mmap_malloc;
+ __realloc_hook = gc_mmap_realloc;
+ __free_hook = gc_mmap_free;
+ __memalign_hook = gc_mmap_memalign;
+}
+
+#endif
+
+}
+
+#ifdef WANT_MALLOC_MMAP
+
+void (*__malloc_initialize_hook)(void) = tuscany::gc_mmap_init_hook;
+
+#endif
+
+#endif /* tuscany_gc_hpp */