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