1*5796c8dcSSimon Schubert /* objalloc.c -- routines to allocate memory for objects 2*5796c8dcSSimon Schubert Copyright 1997 Free Software Foundation, Inc. 3*5796c8dcSSimon Schubert Written by Ian Lance Taylor, Cygnus Solutions. 4*5796c8dcSSimon Schubert 5*5796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify it 6*5796c8dcSSimon Schubert under the terms of the GNU General Public License as published by the 7*5796c8dcSSimon Schubert Free Software Foundation; either version 2, or (at your option) any 8*5796c8dcSSimon Schubert later version. 9*5796c8dcSSimon Schubert 10*5796c8dcSSimon Schubert This program is distributed in the hope that it will be useful, 11*5796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of 12*5796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*5796c8dcSSimon Schubert GNU General Public License for more details. 14*5796c8dcSSimon Schubert 15*5796c8dcSSimon Schubert You should have received a copy of the GNU General Public License 16*5796c8dcSSimon Schubert along with this program; if not, write to the Free Software 17*5796c8dcSSimon Schubert Foundation, 51 Franklin Street - Fifth Floor, 18*5796c8dcSSimon Schubert Boston, MA 02110-1301, USA. */ 19*5796c8dcSSimon Schubert 20*5796c8dcSSimon Schubert #include "config.h" 21*5796c8dcSSimon Schubert #include "ansidecl.h" 22*5796c8dcSSimon Schubert 23*5796c8dcSSimon Schubert #include "objalloc.h" 24*5796c8dcSSimon Schubert 25*5796c8dcSSimon Schubert /* Get a definition for NULL. */ 26*5796c8dcSSimon Schubert #include <stdio.h> 27*5796c8dcSSimon Schubert 28*5796c8dcSSimon Schubert #if VMS 29*5796c8dcSSimon Schubert #include <stdlib.h> 30*5796c8dcSSimon Schubert #include <unixlib.h> 31*5796c8dcSSimon Schubert #else 32*5796c8dcSSimon Schubert 33*5796c8dcSSimon Schubert /* Get a definition for size_t. */ 34*5796c8dcSSimon Schubert #include <stddef.h> 35*5796c8dcSSimon Schubert 36*5796c8dcSSimon Schubert #ifdef HAVE_STDLIB_H 37*5796c8dcSSimon Schubert #include <stdlib.h> 38*5796c8dcSSimon Schubert #else 39*5796c8dcSSimon Schubert /* For systems with larger pointers than ints, this must be declared. */ 40*5796c8dcSSimon Schubert extern PTR malloc (size_t); 41*5796c8dcSSimon Schubert extern void free (PTR); 42*5796c8dcSSimon Schubert #endif 43*5796c8dcSSimon Schubert 44*5796c8dcSSimon Schubert #endif 45*5796c8dcSSimon Schubert 46*5796c8dcSSimon Schubert /* These routines allocate space for an object. Freeing allocated 47*5796c8dcSSimon Schubert space may or may not free all more recently allocated space. 48*5796c8dcSSimon Schubert 49*5796c8dcSSimon Schubert We handle large and small allocation requests differently. If we 50*5796c8dcSSimon Schubert don't have enough space in the current block, and the allocation 51*5796c8dcSSimon Schubert request is for more than 512 bytes, we simply pass it through to 52*5796c8dcSSimon Schubert malloc. */ 53*5796c8dcSSimon Schubert 54*5796c8dcSSimon Schubert /* The objalloc structure is defined in objalloc.h. */ 55*5796c8dcSSimon Schubert 56*5796c8dcSSimon Schubert /* This structure appears at the start of each chunk. */ 57*5796c8dcSSimon Schubert 58*5796c8dcSSimon Schubert struct objalloc_chunk 59*5796c8dcSSimon Schubert { 60*5796c8dcSSimon Schubert /* Next chunk. */ 61*5796c8dcSSimon Schubert struct objalloc_chunk *next; 62*5796c8dcSSimon Schubert /* If this chunk contains large objects, this is the value of 63*5796c8dcSSimon Schubert current_ptr when this chunk was allocated. If this chunk 64*5796c8dcSSimon Schubert contains small objects, this is NULL. */ 65*5796c8dcSSimon Schubert char *current_ptr; 66*5796c8dcSSimon Schubert }; 67*5796c8dcSSimon Schubert 68*5796c8dcSSimon Schubert /* The aligned size of objalloc_chunk. */ 69*5796c8dcSSimon Schubert 70*5796c8dcSSimon Schubert #define CHUNK_HEADER_SIZE \ 71*5796c8dcSSimon Schubert ((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \ 72*5796c8dcSSimon Schubert &~ (OBJALLOC_ALIGN - 1)) 73*5796c8dcSSimon Schubert 74*5796c8dcSSimon Schubert /* We ask for this much memory each time we create a chunk which is to 75*5796c8dcSSimon Schubert hold small objects. */ 76*5796c8dcSSimon Schubert 77*5796c8dcSSimon Schubert #define CHUNK_SIZE (4096 - 32) 78*5796c8dcSSimon Schubert 79*5796c8dcSSimon Schubert /* A request for this amount or more is just passed through to malloc. */ 80*5796c8dcSSimon Schubert 81*5796c8dcSSimon Schubert #define BIG_REQUEST (512) 82*5796c8dcSSimon Schubert 83*5796c8dcSSimon Schubert /* Create an objalloc structure. */ 84*5796c8dcSSimon Schubert 85*5796c8dcSSimon Schubert struct objalloc * 86*5796c8dcSSimon Schubert objalloc_create (void) 87*5796c8dcSSimon Schubert { 88*5796c8dcSSimon Schubert struct objalloc *ret; 89*5796c8dcSSimon Schubert struct objalloc_chunk *chunk; 90*5796c8dcSSimon Schubert 91*5796c8dcSSimon Schubert ret = (struct objalloc *) malloc (sizeof *ret); 92*5796c8dcSSimon Schubert if (ret == NULL) 93*5796c8dcSSimon Schubert return NULL; 94*5796c8dcSSimon Schubert 95*5796c8dcSSimon Schubert ret->chunks = (PTR) malloc (CHUNK_SIZE); 96*5796c8dcSSimon Schubert if (ret->chunks == NULL) 97*5796c8dcSSimon Schubert { 98*5796c8dcSSimon Schubert free (ret); 99*5796c8dcSSimon Schubert return NULL; 100*5796c8dcSSimon Schubert } 101*5796c8dcSSimon Schubert 102*5796c8dcSSimon Schubert chunk = (struct objalloc_chunk *) ret->chunks; 103*5796c8dcSSimon Schubert chunk->next = NULL; 104*5796c8dcSSimon Schubert chunk->current_ptr = NULL; 105*5796c8dcSSimon Schubert 106*5796c8dcSSimon Schubert ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; 107*5796c8dcSSimon Schubert ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; 108*5796c8dcSSimon Schubert 109*5796c8dcSSimon Schubert return ret; 110*5796c8dcSSimon Schubert } 111*5796c8dcSSimon Schubert 112*5796c8dcSSimon Schubert /* Allocate space from an objalloc structure. */ 113*5796c8dcSSimon Schubert 114*5796c8dcSSimon Schubert PTR 115*5796c8dcSSimon Schubert _objalloc_alloc (struct objalloc *o, unsigned long len) 116*5796c8dcSSimon Schubert { 117*5796c8dcSSimon Schubert /* We avoid confusion from zero sized objects by always allocating 118*5796c8dcSSimon Schubert at least 1 byte. */ 119*5796c8dcSSimon Schubert if (len == 0) 120*5796c8dcSSimon Schubert len = 1; 121*5796c8dcSSimon Schubert 122*5796c8dcSSimon Schubert len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); 123*5796c8dcSSimon Schubert 124*5796c8dcSSimon Schubert if (len <= o->current_space) 125*5796c8dcSSimon Schubert { 126*5796c8dcSSimon Schubert o->current_ptr += len; 127*5796c8dcSSimon Schubert o->current_space -= len; 128*5796c8dcSSimon Schubert return (PTR) (o->current_ptr - len); 129*5796c8dcSSimon Schubert } 130*5796c8dcSSimon Schubert 131*5796c8dcSSimon Schubert if (len >= BIG_REQUEST) 132*5796c8dcSSimon Schubert { 133*5796c8dcSSimon Schubert char *ret; 134*5796c8dcSSimon Schubert struct objalloc_chunk *chunk; 135*5796c8dcSSimon Schubert 136*5796c8dcSSimon Schubert ret = (char *) malloc (CHUNK_HEADER_SIZE + len); 137*5796c8dcSSimon Schubert if (ret == NULL) 138*5796c8dcSSimon Schubert return NULL; 139*5796c8dcSSimon Schubert 140*5796c8dcSSimon Schubert chunk = (struct objalloc_chunk *) ret; 141*5796c8dcSSimon Schubert chunk->next = (struct objalloc_chunk *) o->chunks; 142*5796c8dcSSimon Schubert chunk->current_ptr = o->current_ptr; 143*5796c8dcSSimon Schubert 144*5796c8dcSSimon Schubert o->chunks = (PTR) chunk; 145*5796c8dcSSimon Schubert 146*5796c8dcSSimon Schubert return (PTR) (ret + CHUNK_HEADER_SIZE); 147*5796c8dcSSimon Schubert } 148*5796c8dcSSimon Schubert else 149*5796c8dcSSimon Schubert { 150*5796c8dcSSimon Schubert struct objalloc_chunk *chunk; 151*5796c8dcSSimon Schubert 152*5796c8dcSSimon Schubert chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE); 153*5796c8dcSSimon Schubert if (chunk == NULL) 154*5796c8dcSSimon Schubert return NULL; 155*5796c8dcSSimon Schubert chunk->next = (struct objalloc_chunk *) o->chunks; 156*5796c8dcSSimon Schubert chunk->current_ptr = NULL; 157*5796c8dcSSimon Schubert 158*5796c8dcSSimon Schubert o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; 159*5796c8dcSSimon Schubert o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; 160*5796c8dcSSimon Schubert 161*5796c8dcSSimon Schubert o->chunks = (PTR) chunk; 162*5796c8dcSSimon Schubert 163*5796c8dcSSimon Schubert return objalloc_alloc (o, len); 164*5796c8dcSSimon Schubert } 165*5796c8dcSSimon Schubert } 166*5796c8dcSSimon Schubert 167*5796c8dcSSimon Schubert /* Free an entire objalloc structure. */ 168*5796c8dcSSimon Schubert 169*5796c8dcSSimon Schubert void 170*5796c8dcSSimon Schubert objalloc_free (struct objalloc *o) 171*5796c8dcSSimon Schubert { 172*5796c8dcSSimon Schubert struct objalloc_chunk *l; 173*5796c8dcSSimon Schubert 174*5796c8dcSSimon Schubert l = (struct objalloc_chunk *) o->chunks; 175*5796c8dcSSimon Schubert while (l != NULL) 176*5796c8dcSSimon Schubert { 177*5796c8dcSSimon Schubert struct objalloc_chunk *next; 178*5796c8dcSSimon Schubert 179*5796c8dcSSimon Schubert next = l->next; 180*5796c8dcSSimon Schubert free (l); 181*5796c8dcSSimon Schubert l = next; 182*5796c8dcSSimon Schubert } 183*5796c8dcSSimon Schubert 184*5796c8dcSSimon Schubert free (o); 185*5796c8dcSSimon Schubert } 186*5796c8dcSSimon Schubert 187*5796c8dcSSimon Schubert /* Free a block from an objalloc structure. This also frees all more 188*5796c8dcSSimon Schubert recently allocated blocks. */ 189*5796c8dcSSimon Schubert 190*5796c8dcSSimon Schubert void 191*5796c8dcSSimon Schubert objalloc_free_block (struct objalloc *o, PTR block) 192*5796c8dcSSimon Schubert { 193*5796c8dcSSimon Schubert struct objalloc_chunk *p, *small; 194*5796c8dcSSimon Schubert char *b = (char *) block; 195*5796c8dcSSimon Schubert 196*5796c8dcSSimon Schubert /* First set P to the chunk which contains the block we are freeing, 197*5796c8dcSSimon Schubert and set Q to the last small object chunk we see before P. */ 198*5796c8dcSSimon Schubert small = NULL; 199*5796c8dcSSimon Schubert for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next) 200*5796c8dcSSimon Schubert { 201*5796c8dcSSimon Schubert if (p->current_ptr == NULL) 202*5796c8dcSSimon Schubert { 203*5796c8dcSSimon Schubert if (b > (char *) p && b < (char *) p + CHUNK_SIZE) 204*5796c8dcSSimon Schubert break; 205*5796c8dcSSimon Schubert small = p; 206*5796c8dcSSimon Schubert } 207*5796c8dcSSimon Schubert else 208*5796c8dcSSimon Schubert { 209*5796c8dcSSimon Schubert if (b == (char *) p + CHUNK_HEADER_SIZE) 210*5796c8dcSSimon Schubert break; 211*5796c8dcSSimon Schubert } 212*5796c8dcSSimon Schubert } 213*5796c8dcSSimon Schubert 214*5796c8dcSSimon Schubert /* If we can't find the chunk, the caller has made a mistake. */ 215*5796c8dcSSimon Schubert if (p == NULL) 216*5796c8dcSSimon Schubert abort (); 217*5796c8dcSSimon Schubert 218*5796c8dcSSimon Schubert if (p->current_ptr == NULL) 219*5796c8dcSSimon Schubert { 220*5796c8dcSSimon Schubert struct objalloc_chunk *q; 221*5796c8dcSSimon Schubert struct objalloc_chunk *first; 222*5796c8dcSSimon Schubert 223*5796c8dcSSimon Schubert /* The block is in a chunk containing small objects. We can 224*5796c8dcSSimon Schubert free every chunk through SMALL, because they have certainly 225*5796c8dcSSimon Schubert been allocated more recently. After SMALL, we will not see 226*5796c8dcSSimon Schubert any chunks containing small objects; we can free any big 227*5796c8dcSSimon Schubert chunk if the current_ptr is greater than or equal to B. We 228*5796c8dcSSimon Schubert can then reset the new current_ptr to B. */ 229*5796c8dcSSimon Schubert 230*5796c8dcSSimon Schubert first = NULL; 231*5796c8dcSSimon Schubert q = (struct objalloc_chunk *) o->chunks; 232*5796c8dcSSimon Schubert while (q != p) 233*5796c8dcSSimon Schubert { 234*5796c8dcSSimon Schubert struct objalloc_chunk *next; 235*5796c8dcSSimon Schubert 236*5796c8dcSSimon Schubert next = q->next; 237*5796c8dcSSimon Schubert if (small != NULL) 238*5796c8dcSSimon Schubert { 239*5796c8dcSSimon Schubert if (small == q) 240*5796c8dcSSimon Schubert small = NULL; 241*5796c8dcSSimon Schubert free (q); 242*5796c8dcSSimon Schubert } 243*5796c8dcSSimon Schubert else if (q->current_ptr > b) 244*5796c8dcSSimon Schubert free (q); 245*5796c8dcSSimon Schubert else if (first == NULL) 246*5796c8dcSSimon Schubert first = q; 247*5796c8dcSSimon Schubert 248*5796c8dcSSimon Schubert q = next; 249*5796c8dcSSimon Schubert } 250*5796c8dcSSimon Schubert 251*5796c8dcSSimon Schubert if (first == NULL) 252*5796c8dcSSimon Schubert first = p; 253*5796c8dcSSimon Schubert o->chunks = (PTR) first; 254*5796c8dcSSimon Schubert 255*5796c8dcSSimon Schubert /* Now start allocating from this small block again. */ 256*5796c8dcSSimon Schubert o->current_ptr = b; 257*5796c8dcSSimon Schubert o->current_space = ((char *) p + CHUNK_SIZE) - b; 258*5796c8dcSSimon Schubert } 259*5796c8dcSSimon Schubert else 260*5796c8dcSSimon Schubert { 261*5796c8dcSSimon Schubert struct objalloc_chunk *q; 262*5796c8dcSSimon Schubert char *current_ptr; 263*5796c8dcSSimon Schubert 264*5796c8dcSSimon Schubert /* This block is in a large chunk by itself. We can free 265*5796c8dcSSimon Schubert everything on the list up to and including this block. We 266*5796c8dcSSimon Schubert then start allocating from the next chunk containing small 267*5796c8dcSSimon Schubert objects, setting current_ptr from the value stored with the 268*5796c8dcSSimon Schubert large chunk we are freeing. */ 269*5796c8dcSSimon Schubert 270*5796c8dcSSimon Schubert current_ptr = p->current_ptr; 271*5796c8dcSSimon Schubert p = p->next; 272*5796c8dcSSimon Schubert 273*5796c8dcSSimon Schubert q = (struct objalloc_chunk *) o->chunks; 274*5796c8dcSSimon Schubert while (q != p) 275*5796c8dcSSimon Schubert { 276*5796c8dcSSimon Schubert struct objalloc_chunk *next; 277*5796c8dcSSimon Schubert 278*5796c8dcSSimon Schubert next = q->next; 279*5796c8dcSSimon Schubert free (q); 280*5796c8dcSSimon Schubert q = next; 281*5796c8dcSSimon Schubert } 282*5796c8dcSSimon Schubert 283*5796c8dcSSimon Schubert o->chunks = (PTR) p; 284*5796c8dcSSimon Schubert 285*5796c8dcSSimon Schubert while (p->current_ptr != NULL) 286*5796c8dcSSimon Schubert p = p->next; 287*5796c8dcSSimon Schubert 288*5796c8dcSSimon Schubert o->current_ptr = current_ptr; 289*5796c8dcSSimon Schubert o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr; 290*5796c8dcSSimon Schubert } 291*5796c8dcSSimon Schubert } 292