00001 /* 00002 * Copyright (c) 1997, 1998, 1999, 2000, David E. Lowell 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 00015 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00016 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00017 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 00018 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00019 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00020 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00021 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00022 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00023 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00024 * SUCH DAMAGE. 00025 * 00026 * Vista library, version 0.6.1, September 2000 00027 */ 00028 00029 /* 00030 * vistaheap.c 00031 * 00032 * This module contains the code for a fast vistaheap allocator that can take 00033 * its vistaheap management structure as an argument, letting the user keep 00034 * the vistaheap struct anywhere the user likes. This vistaheap system gets its 00035 * memory from an mmapped file that is handed to its initialization routine. 00036 * This code is poorly documented. 00037 */ 00038 00039 #include <stdio.h> 00040 #include <unistd.h> 00041 #include <sys/stat.h> 00042 #include <itm.h> 00043 #include "vistaheap.h" 00044 00045 /* 00046 * Overview of this vistaheap management system 00047 * 00048 * This vistaheap is designed to be fast, small, and to let vistaheap metadata 00049 * live anywhere the user likes. The memory it provides the user comes 00050 * from a file mapped into the process' address space with mmap(). 00051 * This vistaheap automatically extends the end of the file (and vistaheap) as 00052 * user needs grow. It makes no attempt to shorten the file as user 00053 * needs shrink however. It also never unmaps any portion of the vistaheap 00054 * to return memory to the system. 00055 * 00056 * All memory requests are quantized to the nearest power of two size. 00057 * The smallest allocatable size is eight bytes. For example, a request 00058 * for 150k results in 256k being returned to the user. All allocations 00059 * are at least quadword (8 bytes) aligned. Those allocations that are 00060 * 8k or more in size are page aligned. 00061 * 00062 * This vistaheap's routines are extremely fast, at a cost of being somewhat 00063 * extravagant in its space usage. This vistaheap does not keep track of 00064 * the size of each allocation as most vistaheaps do (for example, by 00065 * storing the size of the allocation just before the start of the 00066 * returned chunk of memory). Therefore the size of each allocation 00067 * needs to be passed to the vistaheap_free() routine when the allocation 00068 * is returned to the vistaheap. Although this is a little more work than 00069 * one usually has to do with a vistaheap, the size of each allocation is 00070 * usually known statically. We impose this constraint because keeping 00071 * the size of each allocation with the users chunk of memory 00072 * essentially puts vistaheap metadata in a location in which it could be 00073 * readily corrupted by the user. The alternative might be to keep 00074 * some sort of hash table for this information, but that might add 00075 * significantly to the overhead of this extremely lightweight package. 00076 */ 00077 00078 /* 00079 * vistaheap_init() 00080 * 00081 * h - pointer to vistaheap structure that will manage this vistaheap 00082 * base - pointer to base of mapped region where vistaheap will live 00083 * limit - pointer to end of mapped region 00084 * allocator - vistaheap from which this vistaheap's internal data will be 00085 * allocated. Can be the same as h. 00086 * 00087 * This function initializes a vistaheap management structure so that future 00088 * mallocs and frees can be made with this vistaheap. It returns nothing. 00089 * 'limit' can point to the same location as 'base', indicating that 00090 * no portion of the region has yet been . It will be mapped 00091 * automatically the first time memory is allocated from this vistaheap. 00092 * Alternately, 'base' could point somewhere into a file already mapped. 00093 * In this case, 'limit' should point to the end of the mapped region. 00094 */ 00095 __attribute__((tm_callable)) 00096 void* vistaheap_init(vistaheap* h, void* base, void *hardlimit, vistaheap* allocator) 00097 { 00098 int i; 00099 00100 for (i = 0; i < NBUCKETS; i++) { 00101 h->bucketlists[i] = NULL; 00102 } 00103 h->base = base; 00104 h->limit = base; 00105 h->hardlimit = hardlimit; 00106 h->key = NULL; 00107 h->nlist = NULL; 00108 h->allocator = allocator; 00109 00110 return (void *) h; 00111 } 00112 00113 /* 00114 * log2() 00115 * 00116 * Compute the integer log base two of 'val'. 00117 */ 00118 __attribute__((tm_pure)) 00119 static int log2(int val) 00120 { 00121 int x, i; 00122 00123 for (x = 1, i = 0; val > x; x <<= 1, i++); 00124 return i; 00125 } 00126 00127 /* 00128 * pow2() 00129 * 00130 * Compute 2 to the power 'pow'. 00131 */ 00132 __attribute__((tm_pure)) 00133 static int pow2(int pow) 00134 { 00135 return (1 << pow); 00136 } 00137 00138 /* 00139 * morecore() - add memory to this vistaheap 00140 * 00141 * h - vistaheap to which to add memory from the mapped file 00142 * pages - number of pages to add to the vistaheap 00143 * 00144 * This function adds 'pages' pages of memory to the vistaheap 'h'. 00145 * It returns a pointer to the new pages, or NULL on failure. 00146 */ 00147 __attribute__((tm_callable)) 00148 void* morecore(vistaheap* h, int pages) 00149 { 00150 long len; 00151 void* result; 00152 00153 len = pages * EXTENDSIZE; 00154 result = h->limit; 00155 00156 h->limit += len; 00157 if (h->limit > h->hardlimit) { 00158 h->limit = h->hardlimit; 00159 result = NULL; 00160 } 00161 00162 return result; 00163 } 00164 00165 00166 /* 00167 * nalloc() - allocate a nugget from this vistaheap 00168 * 00169 * h - vistaheap from which to grab a nugget 00170 * 00171 * This function allocates and returns one nugget from vistaheap 'h'. 00172 * 00173 * The free lists for this vistaheap consist of linked lists of 'nuggets'. 00174 * Each nugget (node) in the linked list points to one free chunk of 00175 * memory in the vistaheap that could be returned to the user during a 00176 * subsequent vistaheap_malloc() call. The vistaheap also maintains a free list 00177 * of nuggets that can be allocated and freed internally as needed 00178 * to maintain the free lists. The memory for these nuggets comes 00179 * from this vistaheap's 'allocator' which is specified when the vistaheap is 00180 * initialized. The allocator for this vistaheap is another vistaheap from 00181 * which all internal data (the nuggets) will be allocated. A vistaheap 00182 * can be the allocator for itself. That just means that nuggets will 00183 * be interspersed with user data. Should a nugget be requested with 00184 * none waiting on the free list, the allocator's mapped region will 00185 * automatically be extended to accomodate the new nugget(s). 00186 */ 00187 __attribute__((tm_callable)) 00188 static nugget* nalloc(vistaheap* h) 00189 { 00190 nugget* result; 00191 00192 if (h->nlist != NULL) { 00193 /* Get nugget off the free list */ 00194 result = h->nlist; 00195 h->nlist = result->next; 00196 } 00197 else { 00198 /* 00199 * Extend allocator by one page, and break it up 00200 * new page into nuggets. 00201 */ 00202 nugget *new, *mem, *local_mem; 00203 int i, chunks; 00204 00205 mem = (nugget*) morecore(h->allocator, 1); 00206 if (mem == NULL) { 00207 __tm_waiver fprintf(stderr, "nalloc: morecore failed.\n"); 00208 return NULL; 00209 } 00210 /* 00211 * HACK: Here we have a nice or ugly hack depending on the optical angle 00212 * you view it. The call to 'morecore' above extends the pregion limits 00213 * which is done inside a transaction to ensure the atomicity of the 00214 * operation in case of failure (we are always called from the 00215 * transactional path). Then the following block creates new nuggets 00216 * in the newly allocated region. Since the update of the region limits 00217 * is done transactionally, there is no reason to include the following 00218 * inside the transaction. However there is a slight issue when running 00219 * the following code non-transactionally: variable 'mem' was written 00220 * transactionally, so we need to read it using the TM system to ensure 00221 * we read the correct version independently of the version management 00222 * done by the TM system. 00223 */ 00224 __tm_waiver 00225 { 00226 _ITM_transaction *tx = _ITM_getTransaction(); 00227 _ITM_memcpyRtWn(tx, &local_mem, &mem, sizeof(nugget *)); 00228 chunks = EXTENDSIZE / sizeof(nugget); 00229 for (i = 0; i < chunks; i++) { 00230 new = &local_mem[i]; 00231 new->addr = NULL; 00232 if (i == chunks - 1) 00233 new->next = NULL; 00234 else 00235 new->next = &mem[i+1]; 00236 } 00237 } 00238 h->nlist = mem; 00239 00240 result = h->nlist; 00241 h->nlist = result->next; 00242 } 00243 00244 return result; 00245 } 00246 00247 /* 00248 * nfree() 00249 * 00250 * Return nugget pointed to by 'n' to the nugget free list for 'h'. 00251 */ 00252 __attribute__((tm_callable)) 00253 static void nfree(vistaheap *h, nugget *n) 00254 { 00255 n->next = h->nlist; 00256 h->nlist = n; 00257 } 00258 00259 00260 /* 00261 * vistaheap_malloc() 00262 * 00263 * Allocated at least 'size' bytes from vistaheap 'h'. 00264 */ 00265 __attribute__((tm_callable)) 00266 void* vistaheap_malloc(vistaheap* h, int size) 00267 { 00268 int bucket; 00269 nugget* n; 00270 void* result; 00271 00272 if (size == 0) 00273 return NULL; 00274 00275 bucket = log2(size); 00276 bucket = (bucket < BUCKET_MIN ? BUCKET_MIN : bucket); 00277 n = h->bucketlists[bucket]; 00278 if (n != NULL) { 00279 h->bucketlists[bucket] = n->next; 00280 result = n->addr; 00281 nfree(h, n); 00282 } 00283 else { 00284 int bsize, space, chunks, i; 00285 nugget *last_nugget, *newn; 00286 char* mem; 00287 00288 /* We need more storage */ 00289 if (size <= EXTENDSIZE) 00290 space = EXTENDSIZE; 00291 else 00292 space = pow2(bucket); 00293 mem = morecore(h, space / EXTENDSIZE); 00294 if (mem == NULL) 00295 return NULL; 00296 00297 bsize = pow2(bucket); 00298 chunks = space / bsize; 00299 00300 newn = nalloc(h); 00301 if (newn == NULL) 00302 return NULL; 00303 newn->addr = mem; 00304 newn->next = NULL; 00305 h->bucketlists[bucket] = newn; 00306 00307 last_nugget = newn; 00308 for (i = 1; i < chunks; i++) { 00309 newn = nalloc(h); 00310 if (newn == NULL) 00311 break; 00312 newn->addr = &mem[i * bsize]; 00313 newn->next = NULL; 00314 last_nugget->next = newn; 00315 last_nugget = newn; 00316 } 00317 00318 n = h->bucketlists[bucket]; 00319 if (n == NULL) 00320 result = NULL; 00321 else { 00322 result = n->addr; 00323 h->bucketlists[bucket] = n->next; 00324 nfree(h, n); 00325 } 00326 } 00327 00328 return result; 00329 } 00330 00331 00332 /* 00333 * vistaheap_free() 00334 * 00335 * Return 'size' bytes of memory pointed to by 'p' to vistaheap 'h'. 00336 */ 00337 __attribute__((tm_callable)) 00338 void vistaheap_free(vistaheap* h, void* p, int size) 00339 { 00340 nugget* n; 00341 int bucket; 00342 00343 n = nalloc(h); 00344 if (n == NULL) { 00345 __tm_waiver fprintf(stderr, "vistaheap_free: nalloc failed.\n"); 00346 return; 00347 } 00348 bucket = log2(size); 00349 bucket = (bucket < BUCKET_MIN ? BUCKET_MIN : bucket); 00350 n->addr = p; 00351 n->next = h->bucketlists[bucket]; 00352 h->bucketlists[bucket] = n; 00353 } 00354