diff options
Diffstat (limited to 'intern/memutil')
-rw-r--r-- | intern/memutil/MEM_Allocator.h | 89 | ||||
-rw-r--r-- | intern/memutil/MEM_CacheLimiter.h | 170 | ||||
-rw-r--r-- | intern/memutil/MEM_CacheLimiterC-Api.h | 141 | ||||
-rw-r--r-- | intern/memutil/SConscript | 2 | ||||
-rw-r--r-- | intern/memutil/intern/MEM_CacheLimiterC-Api.cpp | 195 | ||||
-rw-r--r-- | intern/memutil/intern/Makefile | 2 |
6 files changed, 597 insertions, 2 deletions
diff --git a/intern/memutil/MEM_Allocator.h b/intern/memutil/MEM_Allocator.h new file mode 100644 index 00000000000..40716496d16 --- /dev/null +++ b/intern/memutil/MEM_Allocator.h @@ -0,0 +1,89 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_Allocator_h_included__ +#define __MEM_Allocator_h_included__ 1 + +#include "guardedalloc/MEM_guardedalloc.h" + +template<typename _Tp> +struct MEM_Allocator +{ + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp value_type; + + template<typename _Tp1> + struct rebind { + typedef MEM_Allocator<_Tp1> other; + }; + + MEM_Allocator() throw() {} + MEM_Allocator(const MEM_Allocator& __a) throw() {} + + template<typename _Tp1> + MEM_Allocator(const MEM_Allocator<_Tp1> __a) throw() { } + + ~MEM_Allocator() throw() {} + + pointer address(reference __x) const { return &__x; } + + const_pointer address(const_reference __x) const { return &__x; } + + // NB: __n is permitted to be 0. The C++ standard says nothing + // about what the return value is when __n == 0. + _Tp* allocate(size_type __n, const void* = 0) { + _Tp* __ret = 0; + if (__n) + __ret = static_cast<_Tp*>( + MEM_mallocN(__n * sizeof(_Tp), + "STL MEM_Allocator")); + return __ret; + } + + // __p is not permitted to be a null pointer. + void deallocate(pointer __p, size_type){ + MEM_freeN(__p); + } + + size_type max_size() const throw() { + return size_t(-1) / sizeof(_Tp); + } + + void construct(pointer __p, const _Tp& __val) { + new(__p) _Tp(__val); + } + + void destroy(pointer __p) { + __p->~_Tp(); + } +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiter.h b/intern/memutil/MEM_CacheLimiter.h new file mode 100644 index 00000000000..3026e827c3f --- /dev/null +++ b/intern/memutil/MEM_CacheLimiter.h @@ -0,0 +1,170 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_h_included__ +#define __MEM_cache_limiter_h_included__ 1 + +/** + * @section MEM_CacheLimiter + * This class defines a generic memory cache management system + * to limit memory usage to a fixed global maximum. + * + * Please use the C-API in MEM_CacheLimiterC-Api.h for code written in C. + * + * Usage example: + * + * class BigFatImage { + * public: + * ~BigFatImage() { tell_everyone_we_are_gone(this); } + * }; + * + * void doit() { + * MEM_Cache<BigFatImage> BigFatImages; + * + * MEM_Cache_Handle<BigFatImage>* h = BigFatImages.insert(new BigFatImage); + * + * BigFatImages.enforce_limits(); + * h->ref(); + * + * work with image... + * + * h->unref(); + * + * leave image in cache. + */ + +#include <list> +#include "MEM_Allocator.h" + +template<class T> +class MEM_CacheLimiter; + +#ifndef __MEM_cache_limiter_c_api_h_included__ +extern "C" { + extern void MEM_CacheLimiter_set_maximum(int m); + extern int MEM_CacheLimiter_get_maximum(); +}; +#endif + +template<class T> +class MEM_CacheLimiterHandle { +public: + explicit MEM_CacheLimiterHandle(T * data_, + MEM_CacheLimiter<T> * parent_) + : data(data_), refcount(0), parent(parent_) { } + + void ref() { + refcount++; + } + void unref() { + refcount--; + } + T * get() { + return data; + } + const T * get() const { + return data; + } + int get_refcount() const { + return refcount; + } + bool can_destroy() const { + return !data || !refcount; + } + bool destroy_if_possible() { + if (can_destroy()) { + delete data; + data = 0; + unmanage(); + return true; + } + return false; + } + void unmanage() { + parent->unmanage(this); + } + void touch() { + parent->touch(this); + } +private: + friend class MEM_CacheLimiter<T>; + + T * data; + int refcount; + typename std::list<MEM_CacheLimiterHandle<T> *, + MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator me; + MEM_CacheLimiter<T> * parent; +}; + +template<class T> +class MEM_CacheLimiter { +public: + typedef typename std::list<MEM_CacheLimiterHandle<T> *, + MEM_Allocator<MEM_CacheLimiterHandle<T> *> >::iterator iterator; + ~MEM_CacheLimiter() { + for (iterator it = queue.begin(); it != queue.end(); it++) { + delete *it; + } + } + MEM_CacheLimiterHandle<T> * insert(T * elem) { + queue.push_back(new MEM_CacheLimiterHandle<T>(elem, this)); + iterator it = queue.end(); + --it; + queue.back()->me = it; + return queue.back(); + } + void unmanage(MEM_CacheLimiterHandle<T> * handle) { + queue.erase(handle->me); + delete handle; + } + void enforce_limits() { + // this is rather _ugly_! + extern int mem_in_use; + + int max = MEM_CacheLimiter_get_maximum(); + if (max == 0) { + return; + } + for (iterator it = queue.begin(); + it != queue.end() && mem_in_use > max;) { + iterator jt = it; + ++it; + (*jt)->destroy_if_possible(); + } + } + void touch(MEM_CacheLimiterHandle<T> * handle) { + queue.push_back(handle); + queue.erase(handle->me); + iterator it = queue.end(); + --it; + handle->me = it; + } +private: + std::list<MEM_CacheLimiterHandle<T>*, + MEM_Allocator<MEM_CacheLimiterHandle<T> *> > queue; +}; + +#endif diff --git a/intern/memutil/MEM_CacheLimiterC-Api.h b/intern/memutil/MEM_CacheLimiterC-Api.h new file mode 100644 index 00000000000..c21b91491e8 --- /dev/null +++ b/intern/memutil/MEM_CacheLimiterC-Api.h @@ -0,0 +1,141 @@ +/** + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005 + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#ifndef __MEM_cache_limiter_c_api_h_included__ +#define __MEM_cache_limiter_c_api_h_included__ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct MEM_CacheLimiter_s; +struct MEM_CacheLimiterHandle_s; + +typedef struct MEM_CacheLimiter_s MEM_CacheLimiterC; +typedef struct MEM_CacheLimiterHandle_s MEM_CacheLimiterHandleC; + +#ifndef __MEM_cache_limiter_h_included__ +extern void MEM_CacheLimiter_set_maximum(int m); +extern int MEM_CacheLimiter_get_maximum(); +#endif +/** + * Create new MEM_CacheLimiter object + * managed objects are destructed with the data_destructor + * + * @param data_destructor + * @return A new MEM_CacheLimter object + */ + +extern MEM_CacheLimiterC * new_MEM_CacheLimiter( + void (*data_destructor) (void * data)); + +/** + * Delete MEM_CacheLimiter + * + * Frees the memory of the CacheLimiter but does not touch managed objects! + * + * @param This "This" pointer + */ + +extern void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This); + +/** + * Manage object + * + * @param This "This" pointer, data data object to manage + * @return CacheLimiterHandle to ref, unref, touch the managed object + */ + +extern MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data); + +/** + * Free objects until memory constraints are satisfied + * + * @param This "This" pointer + */ + +extern void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This); + +/** + * Unmanage object previously inserted object. + * Does _not_ delete managed object! + * + * @param This "This" pointer, handle of object + */ + +extern void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle); + + +/** + * Raise priority of object (put it at the tail of the deletion chain) + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle); + +/** + * Increment reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle); + +/** + * Decrement reference counter. Objects with reference counter != 0 are _not_ + * deleted. + * + * @param handle of object + */ + +extern void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle); + +/** + * Get reference counter. + * + * @param This "This" pointer, handle of object + */ + +extern int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle); + +/** + * Get pointer to managed object + * + * @param handle of object + */ + +extern void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/memutil/SConscript b/intern/memutil/SConscript index 4d17f13f214..dace305e91d 100644 --- a/intern/memutil/SConscript +++ b/intern/memutil/SConscript @@ -3,6 +3,6 @@ Import ('env') sources = env.Glob('intern/*.cpp') -incs = '.' +incs = '. ..' env.BlenderLib ('blender_MEM', sources, Split(incs), [], libtype='intern', priority = 10 ) diff --git a/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp new file mode 100644 index 00000000000..a259569740b --- /dev/null +++ b/intern/memutil/intern/MEM_CacheLimiterC-Api.cpp @@ -0,0 +1,195 @@ +/** + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contributor(s): Peter Schlaile <peter@schlaile.de> 2005 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_CacheLimiter.h" +#include "MEM_CacheLimiterC-Api.h" + +static int & get_max() +{ + static int m = 32*1024*1024; + return m; +} + +void MEM_CacheLimiter_set_maximum(int m) +{ + get_max() = m; +} + +int MEM_CacheLimiter_get_maximum() +{ + return get_max(); +} + +class MEM_CacheLimiterHandleCClass; +class MEM_CacheLimiterCClass; + +typedef MEM_CacheLimiterHandle<MEM_CacheLimiterHandleCClass> handle_t; +typedef MEM_CacheLimiter<MEM_CacheLimiterHandleCClass> cache_t; +typedef std::list<MEM_CacheLimiterHandleCClass*, + MEM_Allocator<MEM_CacheLimiterHandleCClass* > > list_t; + +class MEM_CacheLimiterCClass { +public: + MEM_CacheLimiterCClass(void (*data_destructor_) (void * data)) + : data_destructor(data_destructor_) { + } + ~MEM_CacheLimiterCClass(); + + handle_t * insert(void * data); + + void destruct(void * data, + list_t::iterator it); + + cache_t * get_cache() { + return &cache; + } +private: + void (*data_destructor) (void * data); + + MEM_CacheLimiter<MEM_CacheLimiterHandleCClass> cache; + + list_t cclass_list; +}; + +class MEM_CacheLimiterHandleCClass { +public: + MEM_CacheLimiterHandleCClass(void * data_, + MEM_CacheLimiterCClass * parent_) + : data(data_), parent(parent_) { } + ~MEM_CacheLimiterHandleCClass(); + void set_iter(list_t::iterator it_) { + it = it_; + } + void set_data(void * data_) { + data = data_; + } + void * get_data() const { + return data; + } +private: + void * data; + MEM_CacheLimiterCClass * parent; + list_t::iterator it; +}; + +handle_t * MEM_CacheLimiterCClass::insert(void * data) +{ + cclass_list.push_back(new MEM_CacheLimiterHandleCClass(data, this)); + list_t::iterator it = cclass_list.end(); + --it; + cclass_list.back()->set_iter(it); + + return cache.insert(cclass_list.back()); +} + +void MEM_CacheLimiterCClass::destruct(void * data, list_t::iterator it) +{ + data_destructor(data); + cclass_list.erase(it); +} + +MEM_CacheLimiterHandleCClass::~MEM_CacheLimiterHandleCClass() +{ + if (data) { + parent->destruct(data, it); + } +} + +MEM_CacheLimiterCClass::~MEM_CacheLimiterCClass() +{ + // should not happen, but don't leak memory in this case... + for (list_t::iterator it = cclass_list.begin(); + it != cclass_list.end(); it++) { + (*it)->set_data(0); + delete *it; + } +} + +// ---------------------------------------------------------------------- + +static inline MEM_CacheLimiterCClass* cast(MEM_CacheLimiterC * l) +{ + return (MEM_CacheLimiterCClass*) l; +} + +static inline handle_t* cast(MEM_CacheLimiterHandleC * l) +{ + return (handle_t*) l; +} + +MEM_CacheLimiterC * new_MEM_CacheLimiter( + void (*data_destructor) (void * data)) +{ + return (MEM_CacheLimiterC*) new MEM_CacheLimiterCClass( + data_destructor); +} + +void delete_MEM_CacheLimiter(MEM_CacheLimiterC * This) +{ + delete cast(This); +} + +MEM_CacheLimiterHandleC * MEM_CacheLimiter_insert( + MEM_CacheLimiterC * This, void * data) +{ + return (MEM_CacheLimiterHandleC *) cast(This)->insert(data); +} + +void MEM_CacheLimiter_enforce_limits(MEM_CacheLimiterC * This) +{ + cast(This)->get_cache()->enforce_limits(); +} + +void MEM_CacheLimiter_unmanage(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unmanage(); +} + +void MEM_CacheLimiter_touch(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->touch(); +} + +void MEM_CacheLimiter_ref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->ref(); +} + +void MEM_CacheLimiter_unref(MEM_CacheLimiterHandleC * handle) +{ + cast(handle)->unref(); +} + +int MEM_CacheLimiter_get_refcount(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get_refcount(); +} + + +void * MEM_CacheLimiter_get(MEM_CacheLimiterHandleC * handle) +{ + return cast(handle)->get()->get_data(); +} diff --git a/intern/memutil/intern/Makefile b/intern/memutil/intern/Makefile index 0d0d3af6327..71ffa6fa7e4 100644 --- a/intern/memutil/intern/Makefile +++ b/intern/memutil/intern/Makefile @@ -38,5 +38,5 @@ include nan_compile.mk CCFLAGS += $(LEVEL_2_CPP_WARNINGS) -CPPFLAGS += -I.. +CPPFLAGS += -I.. -I../.. |