1 /*=========================================================================== 2 * 3 * PUBLIC DOMAIN NOTICE 4 * National Center for Biotechnology Information 5 * 6 * This software/database is a "United States Government Work" under the 7 * terms of the United States Copyright Act. It was written as part of 8 * the author's official duties as a United States Government employee and 9 * thus cannot be copyrighted. This software/database is freely available 10 * to the public for use. The National Library of Medicine and the U.S. 11 * Government have not placed any restriction on its use or reproduction. 12 * 13 * Although all reasonable efforts have been taken to ensure the accuracy 14 * and reliability of the software and data, the NLM and the U.S. 15 * Government do not and cannot warrant the performance or results that 16 * may be obtained by using this software or data. The NLM and the U.S. 17 * Government disclaim all warranties, express or implied, including 18 * warranties of performance, merchantability or fitness for any particular 19 * purpose. 20 * 21 * Please cite the author in any work or product based on this material. 22 * 23 * =========================================================================== 24 * 25 */ 26 27 #include "pmemmgr.hpp" 28 #include <kfc/memory.hpp> 29 #include <kfc/callstk.hpp> 30 #include <kfc/caps.hpp> 31 #include <kfc/rsrc.hpp> 32 33 #include <stdlib.h> 34 #include <string.h> 35 36 #if UNIX 37 #include <sys/resource.h> 38 #endif 39 40 namespace vdb3 41 { 42 43 const caps_t CONST_MEM_CAPS 44 = CAP_PROP_READ 45 | CAP_READ 46 | CAP_SUBRANGE 47 | CAP_CAST 48 ; 49 50 const caps_t NEW_MEM_CAPS 51 = CONST_MEM_CAPS 52 | CAP_WRITE 53 | CAP_RESIZE 54 ; 55 56 57 /*------------------------------------------------------------------ 58 * const_memory_t 59 * an object representing a range of address space 60 */ 61 class const_memory_t : implements MemoryItf 62 { 63 public: 64 65 virtual void resize ( const bytes_t & new_size, bool clear ); 66 const_memory_t ( const void * ptr, const bytes_t & size ); 67 ~ const_memory_t (); 68 69 protected: 70 71 virtual void * get_mapped_memory ( bytes_t * size ) const; 72 73 const void * ptr; 74 bytes_t size; 75 }; 76 resize(const bytes_t & new_size,bool clear)77 void const_memory_t :: resize ( const bytes_t & new_size, bool clear ) 78 { 79 FUNC_ENTRY (); 80 CONST_THROW ( xc_internal_err, "should never be called" ); 81 } 82 const_memory_t(const void * _ptr,const bytes_t & _size)83 const_memory_t :: const_memory_t ( const void * _ptr, const bytes_t & _size ) 84 : ptr ( _ptr ) 85 , size ( _size ) 86 { 87 } 88 ~const_memory_t()89 const_memory_t :: ~ const_memory_t () 90 { 91 ptr = 0; 92 size = ( U64 ) 0; 93 } 94 get_mapped_memory(bytes_t * _size) const95 void * const_memory_t :: get_mapped_memory ( bytes_t * _size ) const 96 { 97 if ( _size != 0 ) 98 * _size = size; 99 return ( void * ) ptr; 100 } 101 102 103 /*------------------------------------------------------------------ 104 * Memory 105 * an object representing a range of address space 106 */ 107 class Memory : public const_memory_t 108 { 109 public: 110 111 virtual void resize ( const bytes_t & new_size, bool clear ); 112 Memory ( void * ptr, const bytes_t & size ); 113 ~ Memory (); 114 }; 115 resize(const bytes_t & new_size,bool clear)116 void Memory :: resize ( const bytes_t & new_size, bool clear ) 117 { 118 FUNC_ENTRY (); 119 120 MemMgrItf * mmgr = get_mmgr (); 121 assert ( mmgr != 0 ); 122 123 assert ( ptr != 0 ); 124 assert ( new_size != size ); 125 126 ptr = mmgr -> _resize ( ( void * ) ptr, size, new_size, clear ); 127 size = new_size; 128 } 129 Memory(void * _ptr,const bytes_t & _size)130 Memory :: Memory ( void * _ptr, const bytes_t & _size ) 131 : const_memory_t ( _ptr, _size ) 132 { 133 } 134 ~Memory()135 Memory :: ~ Memory () 136 { 137 FUNC_ENTRY (); 138 139 MemMgrItf * mmgr = get_mmgr (); 140 assert ( mmgr != 0 ); 141 142 mmgr -> _free ( ( void * ) ptr, size ); 143 } 144 145 146 /*------------------------------------------------------------------ 147 * PrimordMemMgr 148 */ 149 make_primordial()150 MemMgr PrimordMemMgr :: make_primordial () 151 { 152 assert ( callstk != 0 ); 153 FUNC_ENTRY (); 154 155 // allow for the very first call 156 static atomic_t < I32 > latch = 0; 157 if ( latch . test_and_set ( 0, 1 ) != 0 ) 158 { 159 const char msg [] = "primordial memory manager exists"; 160 if ( rsrc == 0 ) 161 throw msg; 162 CONST_THROW ( xc_program_state_violation, msg ); 163 } 164 165 // determine system memory quota 166 size_t quota = ~ ( size_t ) 0; 167 #if UNIX 168 struct rlimit rlim; 169 int status = getrlimit ( RLIMIT_AS, & rlim ); 170 if ( status == 0 ) 171 quota = rlim . rlim_cur; 172 #endif 173 174 // allocate the object memory 175 PrimordMemMgr * obj; 176 obj = ( PrimordMemMgr * ) calloc ( 1, sizeof * obj ); 177 if ( obj == 0 ) 178 throw "out of memory allocating primordial memory manager"; 179 180 // construct the primordial mmgr 181 new ( obj ) PrimordMemMgr ( quota, quota - sizeof * obj ); 182 183 // embed self into object 184 // DO NOT STORE DUPLICATE 185 // as this would introduce a cycle 186 obj -> mmgr = obj; 187 obj -> obj_size = sizeof * obj; 188 189 // create the reference 190 return obj -> make_mmgr_ref ( obj, CAP_RDWR | CAP_ALLOC ); 191 } 192 193 194 /* alloc 195 */ alloc(const bytes_t & size,bool clear)196 Mem PrimordMemMgr :: alloc ( const bytes_t & size, bool clear ) 197 { 198 FUNC_ENTRY (); 199 200 // allocate a raw block 201 void * block = ( size == ( U64 ) 0 ) ? 0 : _alloc ( size, clear ); 202 203 // create the memory object 204 Memory * obj = new Memory ( block, size ); 205 206 // create the reference 207 return make_mem_ref ( obj, obj, NEW_MEM_CAPS ); 208 } 209 make_const(const void * ptr,const bytes_t & size)210 Mem PrimordMemMgr :: make_const ( const void * ptr, const bytes_t & size ) 211 { 212 FUNC_ENTRY (); 213 214 // create the const memory object 215 const_memory_t * obj = new const_memory_t ( ptr, size ); 216 217 // create the reference 218 return make_mem_ref ( obj, obj, CONST_MEM_CAPS ); 219 } 220 _alloc(const bytes_t & size,bool clear)221 void * PrimordMemMgr :: _alloc ( const bytes_t & size, bool clear ) 222 { 223 FUNC_ENTRY (); 224 225 size_t bytes = size; 226 227 // allocate from quota 228 if ( avail . read_and_sub_ge ( size, size ) < size ) 229 THROW ( xc_mem_quota, "memory quota exhausted allocating %lu bytes", ( U64 ) size ); 230 231 // allocate using process memory manager 232 void * ptr = clear ? calloc ( 1, bytes ) : malloc ( bytes ); 233 if ( ptr == 0 ) 234 { 235 // return bytes to quota 236 avail += bytes; 237 238 // failure 239 THROW ( xc_no_mem, "process memory exhausted allocating %zu bytes", bytes ); 240 } 241 242 return ptr; 243 244 } 245 _resize(void * old_ptr,const bytes_t & old_size,const bytes_t & new_size,bool clear)246 void * PrimordMemMgr :: _resize ( void * old_ptr, const bytes_t & old_size, const bytes_t & new_size, bool clear ) 247 { 248 FUNC_ENTRY (); 249 250 // nothing to do if there is no size change 251 if ( old_size == new_size ) 252 return old_ptr; 253 254 // check for quota 255 if ( ( avail + old_size ) < new_size ) 256 THROW ( xc_mem_quota, "memory quota exhausted reallocating %lu to %lu bytes", ( U64 ) old_size, ( U64 ) new_size ); 257 258 size_t new_bytes = new_size; 259 260 // not supposed to be called with bad values 261 assert ( old_ptr != 0 || old_size == ( U64 ) 0 ); 262 263 // reallocate using process memory manager 264 // alternatively, we could always allocate and copy, destroying old 265 void * new_ptr = realloc ( old_ptr, new_bytes ); 266 if ( new_ptr == 0 ) 267 THROW ( xc_no_mem, "process memory exhausted reallocating %lu to %lu bytes", ( U64 ) old_size, ( U64 ) new_size ); 268 269 // update bytes remaining 270 if ( old_size > new_size ) 271 avail += old_size - new_size; 272 else 273 { 274 avail -= new_size - old_size; 275 276 // clear extended area 277 if ( clear ) 278 memset ( & ( ( char* ) new_ptr ) [ old_size ], 0, new_size - old_size ); 279 } 280 281 return new_ptr; 282 } 283 _free(void * ptr,const bytes_t & size)284 void PrimordMemMgr :: _free ( void * ptr, const bytes_t & size ) 285 { 286 // not supposed to be called with bad values 287 assert ( ptr != 0 || size == ( U64 ) 0 ); 288 289 // return to the process memory manager 290 // alternatively, could clear before free 291 free ( ptr ); 292 293 // update bytes remaining 294 if ( ( void * ) this != ptr ) 295 avail += size; 296 } 297 PrimordMemMgr(const bytes_t & q,const bytes_t & a)298 PrimordMemMgr :: PrimordMemMgr ( const bytes_t & q, const bytes_t & a ) 299 : quota ( q ) 300 , avail ( a ) 301 { 302 } 303 ~PrimordMemMgr()304 PrimordMemMgr :: ~ PrimordMemMgr () 305 { 306 // TBD - can test if avail != quota 307 quota = 0; 308 avail = 0; 309 } 310 operator delete(void * ptr)311 void PrimordMemMgr :: operator delete ( void * ptr ) 312 { 313 free ( ptr ); 314 } 315 } 316