00001 /* 00002 * Copyright 2003, 2004, 2005, 2006 PathScale, Inc. All Rights Reserved. 00003 */ 00004 00005 /* objalloc.c -- routines to allocate memory for objects 00006 Copyright 1997 Free Software Foundation, Inc. 00007 Written by Ian Lance Taylor, Cygnus Solutions. 00008 00009 This program is free software; you can redistribute it and/or modify it 00010 under the terms of the GNU General Public License as published by the 00011 Free Software Foundation; either version 2, or (at your option) any 00012 later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, 59 Temple Place - Suite 330, 00022 Boston, MA 02111-1307, USA. */ 00023 00024 #include "config.h" 00025 #include "ansidecl.h" 00026 00027 #include "objalloc.h" 00028 00029 /* Get a definition for NULL. */ 00030 #include <stdio.h> 00031 00032 #if VMS 00033 #include <stdlib.h> 00034 #include <unixlib.h> 00035 #else 00036 00037 #ifdef ANSI_PROTOTYPES 00038 /* Get a definition for size_t. */ 00039 #include <stddef.h> 00040 #endif 00041 00042 #ifdef HAVE_STDLIB_H 00043 #include <stdlib.h> 00044 #else 00045 /* For systems with larger pointers than ints, this must be declared. */ 00046 extern PTR malloc PARAMS ((size_t)); 00047 extern void free PARAMS ((PTR)); 00048 #endif 00049 00050 #endif 00051 00052 /* These routines allocate space for an object. Freeing allocated 00053 space may or may not free all more recently allocated space. 00054 00055 We handle large and small allocation requests differently. If we 00056 don't have enough space in the current block, and the allocation 00057 request is for more than 512 bytes, we simply pass it through to 00058 malloc. */ 00059 00060 /* The objalloc structure is defined in objalloc.h. */ 00061 00062 /* This structure appears at the start of each chunk. */ 00063 00064 struct objalloc_chunk 00065 { 00066 /* Next chunk. */ 00067 struct objalloc_chunk *next; 00068 /* If this chunk contains large objects, this is the value of 00069 current_ptr when this chunk was allocated. If this chunk 00070 contains small objects, this is NULL. */ 00071 char *current_ptr; 00072 }; 00073 00074 /* The aligned size of objalloc_chunk. */ 00075 00076 #define CHUNK_HEADER_SIZE \ 00077 ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \ 00078 &~ (OBJALLOC_ALIGN - 1)) 00079 00080 /* We ask for this much memory each time we create a chunk which is to 00081 hold small objects. */ 00082 00083 #define CHUNK_SIZE (4096 - 32) 00084 00085 /* A request for this amount or more is just passed through to malloc. */ 00086 00087 #define BIG_REQUEST (512) 00088 00089 /* Create an objalloc structure. */ 00090 00091 struct objalloc * 00092 objalloc_create () 00093 { 00094 struct objalloc *ret; 00095 struct objalloc_chunk *chunk; 00096 00097 ret = (struct objalloc *) malloc (sizeof *ret); 00098 if (ret == NULL) 00099 return NULL; 00100 00101 ret->chunks = (PTR) malloc (CHUNK_SIZE); 00102 if (ret->chunks == NULL) 00103 { 00104 free (ret); 00105 return NULL; 00106 } 00107 00108 chunk = (struct objalloc_chunk *) ret->chunks; 00109 chunk->next = NULL; 00110 chunk->current_ptr = NULL; 00111 00112 ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; 00113 ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; 00114 00115 return ret; 00116 } 00117 00118 /* Allocate space from an objalloc structure. */ 00119 00120 PTR 00121 _objalloc_alloc (o, len) 00122 struct objalloc *o; 00123 unsigned long len; 00124 { 00125 /* We avoid confusion from zero sized objects by always allocating 00126 at least 1 byte. */ 00127 if (len == 0) 00128 len = 1; 00129 00130 len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); 00131 00132 if (len <= o->current_space) 00133 { 00134 o->current_ptr += len; 00135 o->current_space -= len; 00136 return (PTR) (o->current_ptr - len); 00137 } 00138 00139 if (len >= BIG_REQUEST) 00140 { 00141 char *ret; 00142 struct objalloc_chunk *chunk; 00143 00144 ret = (char *) malloc (CHUNK_HEADER_SIZE + len); 00145 if (ret == NULL) 00146 return NULL; 00147 00148 chunk = (struct objalloc_chunk *) ret; 00149 chunk->next = (struct objalloc_chunk *) o->chunks; 00150 chunk->current_ptr = o->current_ptr; 00151 00152 o->chunks = (PTR) chunk; 00153 00154 return (PTR) (ret + CHUNK_HEADER_SIZE); 00155 } 00156 else 00157 { 00158 struct objalloc_chunk *chunk; 00159 00160 chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE); 00161 if (chunk == NULL) 00162 return NULL; 00163 chunk->next = (struct objalloc_chunk *) o->chunks; 00164 chunk->current_ptr = NULL; 00165 00166 o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; 00167 o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; 00168 00169 o->chunks = (PTR) chunk; 00170 00171 return objalloc_alloc (o, len); 00172 } 00173 } 00174 00175 /* Free an entire objalloc structure. */ 00176 00177 void 00178 objalloc_free (o) 00179 struct objalloc *o; 00180 { 00181 struct objalloc_chunk *l; 00182 00183 l = (struct objalloc_chunk *) o->chunks; 00184 while (l != NULL) 00185 { 00186 struct objalloc_chunk *next; 00187 00188 next = l->next; 00189 free (l); 00190 l = next; 00191 } 00192 00193 free (o); 00194 } 00195 00196 /* Free a block from an objalloc structure. This also frees all more 00197 recently allocated blocks. */ 00198 00199 void 00200 objalloc_free_block (o, block) 00201 struct objalloc *o; 00202 PTR block; 00203 { 00204 struct objalloc_chunk *p, *small; 00205 char *b = (char *) block; 00206 00207 /* First set P to the chunk which contains the block we are freeing, 00208 and set Q to the last small object chunk we see before P. */ 00209 small = NULL; 00210 for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next) 00211 { 00212 if (p->current_ptr == NULL) 00213 { 00214 if (b > (char *) p && b < (char *) p + CHUNK_SIZE) 00215 break; 00216 small = p; 00217 } 00218 else 00219 { 00220 if (b == (char *) p + CHUNK_HEADER_SIZE) 00221 break; 00222 } 00223 } 00224 00225 /* If we can't find the chunk, the caller has made a mistake. */ 00226 if (p == NULL) 00227 abort (); 00228 00229 if (p->current_ptr == NULL) 00230 { 00231 struct objalloc_chunk *q; 00232 struct objalloc_chunk *first; 00233 00234 /* The block is in a chunk containing small objects. We can 00235 free every chunk through SMALL, because they have certainly 00236 been allocated more recently. After SMALL, we will not see 00237 any chunks containing small objects; we can free any big 00238 chunk if the current_ptr is greater than or equal to B. We 00239 can then reset the new current_ptr to B. */ 00240 00241 first = NULL; 00242 q = (struct objalloc_chunk *) o->chunks; 00243 while (q != p) 00244 { 00245 struct objalloc_chunk *next; 00246 00247 next = q->next; 00248 if (small != NULL) 00249 { 00250 if (small == q) 00251 small = NULL; 00252 free (q); 00253 } 00254 else if (q->current_ptr > b) 00255 free (q); 00256 else if (first == NULL) 00257 first = q; 00258 00259 q = next; 00260 } 00261 00262 if (first == NULL) 00263 first = p; 00264 o->chunks = (PTR) first; 00265 00266 /* Now start allocating from this small block again. */ 00267 o->current_ptr = b; 00268 o->current_space = ((char *) p + CHUNK_SIZE) - b; 00269 } 00270 else 00271 { 00272 struct objalloc_chunk *q; 00273 char *current_ptr; 00274 00275 /* This block is in a large chunk by itself. We can free 00276 everything on the list up to and including this block. We 00277 then start allocating from the next chunk containing small 00278 objects, setting current_ptr from the value stored with the 00279 large chunk we are freeing. */ 00280 00281 current_ptr = p->current_ptr; 00282 p = p->next; 00283 00284 q = (struct objalloc_chunk *) o->chunks; 00285 while (q != p) 00286 { 00287 struct objalloc_chunk *next; 00288 00289 next = q->next; 00290 free (q); 00291 q = next; 00292 } 00293 00294 o->chunks = (PTR) p; 00295 00296 while (p->current_ptr != NULL) 00297 p = p->next; 00298 00299 o->current_ptr = current_ptr; 00300 o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr; 00301 } 00302 }
1.5.6