00001 /* -*- mode:C++; c-basic-offset:4 -*- 00002 Shore-MT -- Multi-threaded port of the SHORE storage manager 00003 00004 Copyright (c) 2007-2009 00005 Data Intensive Applications and Systems Labaratory (DIAS) 00006 Ecole Polytechnique Federale de Lausanne 00007 00008 All Rights Reserved. 00009 00010 Permission to use, copy, modify and distribute this software and 00011 its documentation is hereby granted, provided that both the 00012 copyright notice and this permission notice appear in all copies of 00013 the software, derivative works or modified versions, and any 00014 portions thereof, and that both notices appear in supporting 00015 documentation. 00016 00017 This code is distributed in the hope that it will be useful, but 00018 WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS 00020 DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 00021 RESULTING FROM THE USE OF THIS SOFTWARE. 00022 */ 00023 00024 #ifndef __ATOMIC_TRASH_STACK 00025 #define __ATOMIC_TRASH_STACK 00026 00027 #include <atomic_templates.h> 00028 00029 // for placement new support, which some users need 00030 #include <new> 00031 #include <cassert> 00032 #include <stdlib.h> 00033 #include "atomic_container.h" 00034 00035 00036 /** \brief A thread-safe memory pool based on the atomic container, used by 00037 * atomic_class_pool. 00038 * 00039 * \note this code is \e not used by 00040 * the storage manager (or maintained) anymore. The 00041 * code is still distributed with releases only because it is used by an 00042 * important client, the "kits" distributed by DIAS. 00043 * 00044 * Creates a new atomic_container with \e seed pre-allocated 00045 * untyped items of size \e nbytes each. 00046 * It is important to have a non-zero seed value so that 00047 * atomic_container versioning works correctly. 00048 * 00049 * Maintains a global freelist of fixed-sized memory chunks to recycle 00050 * and provides a drop-in replacement for malloc() and free() 00051 * 00052 */ 00053 struct atomic_preallocated_pool : protected atomic_container 00054 { 00055 atomic_preallocated_pool(uint nbytes, long seed=128) 00056 : atomic_container(-sizeof(ptr)), _nbytes(nbytes+sizeof(ptr)) 00057 { 00058 // start with a non-empty pool so threads don't race at the beginning 00059 ptr* head = NULL; 00060 for(int i=0; i < seed; i++) { 00061 vpn u = {alloc()}; 00062 u.p->next = head; 00063 head = u.p; 00064 } 00065 for(int i=0; i < seed; i++) { 00066 ptr* p = head; 00067 head = head->next; 00068 dealloc(p); 00069 } 00070 } 00071 void* alloc() { 00072 void* val = pop(); 00073 if(val) return val; 00074 00075 vpn u = { malloc(_nbytes) }; 00076 if(!u.v) u.v = null(); 00077 return prepare(u); 00078 } 00079 void dealloc(void* val) { push(val); } 00080 00081 ~atomic_preallocated_pool() { 00082 vpn val; 00083 while( (val.v=pop()) ) { 00084 val.n += _offset; // back up to the real start of the pointer 00085 free(val.v); 00086 } 00087 } 00088 00089 uint const _nbytes; 00090 }; 00091 00092 // forward decls... 00093 template<class T> 00094 struct atomic_class_pool; 00095 template<class T> 00096 void* operator new(size_t nbytes, atomic_class_pool<T>& pool); 00097 template<class T> 00098 inline void operator delete(void* ptr, atomic_class_pool<T>& pool); 00099 00100 /** \brief A thread-safe memory pool for typed objects, based on atomic_preallocated_pool. 00101 * 00102 * \note this code is \e not used by 00103 * the storage manager (or maintained) anymore. The 00104 * code is still distributed with releases only because it is used by an 00105 * important client, the "kits" distributed by DIAS. 00106 * 00107 * Provides a replacement for new/delete on the specific class. Note 00108 * that there's actually no way to prevent the user from allocating 00109 * whatever they want, but they will be unable to destroy anything but 00110 * the specified class (and its subclasses). 00111 * 00112 * \code 00113 * Example: 00114 * 00115 * class foo { }; 00116 * atomic_class_pool<foo> pool; 00117 * foo* f = new(pool) foo; 00118 * pool.destroy(f); 00119 * \endcode 00120 */ 00121 template<class T> 00122 struct atomic_class_pool : protected atomic_preallocated_pool { 00123 00124 /** \brief Create a pool for class T. 00125 * 00126 * By default the pool will hand out sizeof(T) bytes at a time; if 00127 * T is a base class and this pool is to be used with subclasses, 00128 * nbytes must be set at least as large as the largest 00129 * class. Oversized allocations will assert(). 00130 * 00131 * \note this code is \e not used by 00132 * the storage manager (or maintained) anymore. The 00133 * code is still distributed with releases only because it is used by an 00134 * important client, the "kits" distributed by DIAS. 00135 */ 00136 atomic_class_pool(long nbytes=sizeof(T), long seed=128) 00137 : atomic_preallocated_pool(nbytes, seed) 00138 { 00139 } 00140 00141 /** \brief Destroys an object (by calling its destructor) and returns its 00142 * memory to the pool. 00143 * 00144 * Undefined behavior results if the object did not come from this 00145 * pool. 00146 * 00147 * \note this code is \e not used by 00148 * the storage manager (or maintained) anymore. The 00149 * code is still distributed with releases only because it is used by an 00150 * important client, the "kits" distributed by DIAS. 00151 */ 00152 void destroy(T* tptr) { 00153 // avoid pointer aliasing problems with the optimizer 00154 union { T* t; void* v; } u = {tptr}; 00155 00156 // destruct the object and deallocate its memory 00157 u.t->~T(); 00158 dealloc(u.v); 00159 } 00160 00161 /** \brief Return the object size given to the constructor. 00162 */ 00163 uint nbytes() { return _nbytes; } 00164 00165 // these guys need to access the underlying preallocated stack 00166 friend void* operator new<>(size_t, atomic_class_pool<T> &); 00167 friend void operator delete<>(void*, atomic_class_pool<T> &); 00168 }; 00169 00170 /** \brief WARNING: When finished, call pool.destroy(t) instead of delete. 00171 * 00172 * \note this code is \e not used by 00173 * the storage manager (or maintained) anymore. The 00174 * code is still distributed with releases only because it is used by an 00175 * important client, the "kits" distributed by DIAS. 00176 * 00177 * \note use placement-style new with the pool. 00178 * \code 00179 * usage: T* t = new(pool) T(...) 00180 * \endcode 00181 */ 00182 00183 template<class T> 00184 inline void* operator new(size_t nbytes, atomic_class_pool<T>& pool) { 00185 assert(pool.nbytes() >= nbytes); 00186 return pool.alloc(); 00187 } 00188 00189 /**\brief Called automatically by the compiler if T's constructor throws 00190 * (otherwise memory would leak). 00191 * 00192 * \note this code is \e not used by 00193 * the storage manager (or maintained) anymore. The 00194 * code is still distributed with releases only because it is used by an 00195 * important client, the "kits" distributed by DIAS. 00196 * 00197 * Unfortunately, there is no "delete(pool)" syntax in C++ so the user 00198 * must still call pool.destroy() 00199 */ 00200 template<class T> 00201 inline void operator delete(void* ptr, atomic_class_pool<T>& pool) { 00202 pool.dealloc(ptr); 00203 } 00204 00205 #endif