|
|
1.1 ! root 1: /* ! 2: ! 3: * Copyright 1992 Atari Corporation. All rights reserved. ! 4: ! 5: */ ! 6: ! 7: ! 8: ! 9: /* ! 10: ! 11: * General-purpose memory allocator, on the MWC arena model, with ! 12: ! 13: * this added feature: ! 14: ! 15: * ! 16: ! 17: * All blocks are coalesced when they're freed. If this results in ! 18: ! 19: * an arena with only one block, and that free, it's returned to the ! 20: ! 21: * OS. ! 22: ! 23: * ! 24: ! 25: * The functions here have the same names and bindings as the MWC ! 26: ! 27: * memory manager, which is the same as the UNIX names and bindings. ! 28: ! 29: * ! 30: ! 31: * MiNT version: used for kmalloc to manage kernel memory in small hunks, ! 32: ! 33: * rather than using a page at a time. ! 34: ! 35: */ ! 36: ! 37: ! 38: ! 39: #include "mint.h" ! 40: ! 41: ! 42: ! 43: #if 0 ! 44: ! 45: #define NALLOC_DEBUG(c) TRACE(("nalloc: %c",c)); ! 46: ! 47: #else ! 48: ! 49: #define NALLOC_DEBUG(c) /* nothing */ ! 50: ! 51: #endif ! 52: ! 53: ! 54: ! 55: #define NKMAGIC 0x19870425L ! 56: ! 57: ! 58: ! 59: /* ! 60: ! 61: * block header: every memory block has one. ! 62: ! 63: * A block is either allocated or on the free ! 64: ! 65: * list of the arena. There is no allocated list: it's not necessary. ! 66: ! 67: * The next pointer is only valid for free blocks: for allocated blocks ! 68: ! 69: * maybe it should hold a verification value..? ! 70: ! 71: * ! 72: ! 73: * Zero-length blocks are possible and free; they hold space which might ! 74: ! 75: * get coalesced usefully later on. ! 76: ! 77: */ ! 78: ! 79: ! 80: ! 81: struct block { ! 82: ! 83: struct block *b_next; /* NULL for last guy; next alloc or next free */ ! 84: ! 85: long b_size; ! 86: ! 87: }; ! 88: ! 89: ! 90: ! 91: /* ! 92: ! 93: * arena header: every arena has one. Each arena is always completely ! 94: ! 95: * filled with blocks; the first starts right after this header. ! 96: ! 97: */ ! 98: ! 99: ! 100: ! 101: struct arena { ! 102: ! 103: struct arena *a_next; ! 104: ! 105: struct block *a_ffirst; ! 106: ! 107: long a_size; ! 108: ! 109: }; ! 110: ! 111: ! 112: ! 113: /* ! 114: ! 115: * Arena linked-list pointer, and block size. ! 116: ! 117: */ ! 118: ! 119: ! 120: ! 121: static struct arena *a_first = (struct arena *)NULL; ! 122: ! 123: ! 124: ! 125: void ! 126: ! 127: nalloc_arena_add(start,len) ! 128: ! 129: void *start; ! 130: ! 131: long len; ! 132: ! 133: { ! 134: ! 135: struct arena *a = start; ! 136: ! 137: struct block *b; ! 138: ! 139: ! 140: ! 141: a->a_next = a_first; ! 142: ! 143: a_first = a; ! 144: ! 145: a->a_ffirst = b = (struct block *)(a+1); ! 146: ! 147: a->a_size = len; ! 148: ! 149: b->b_next = NULL; ! 150: ! 151: b->b_size = (len - sizeof(*a) - sizeof(*b)); ! 152: ! 153: } ! 154: ! 155: ! 156: ! 157: ! 158: ! 159: void * ! 160: ! 161: nalloc(size) ! 162: ! 163: long size; ! 164: ! 165: { ! 166: ! 167: struct arena *a; ! 168: ! 169: struct block *b, *mb, **q; ! 170: ! 171: long temp; ! 172: ! 173: ! 174: ! 175: NALLOC_DEBUG('A'); ! 176: ! 177: ! 178: ! 179: /* force even-sized alloc's */ ! 180: ! 181: size = (size+1) & ~1; ! 182: ! 183: ! 184: ! 185: for (a = a_first; a; a = a->a_next) { ! 186: ! 187: for (b = *(q = &a->a_ffirst); b; b = *(q = &b->b_next)) { ! 188: ! 189: /* if big enough, use it */ ! 190: ! 191: if (b->b_size >= size) { ! 192: ! 193: ! 194: ! 195: /* got one */ ! 196: ! 197: mb = b; ! 198: ! 199: ! 200: ! 201: /* cut the free block into an allocated part & a free part */ ! 202: ! 203: temp = mb->b_size - size - sizeof(struct block); ! 204: ! 205: if (temp >= 0) { ! 206: ! 207: /* large enough to cut */ ! 208: ! 209: NALLOC_DEBUG('c'); ! 210: ! 211: b = (struct block *)(((char *)(b+1)) + size); ! 212: ! 213: b->b_size = temp; ! 214: ! 215: b->b_next = mb->b_next; ! 216: ! 217: *q = b; ! 218: ! 219: mb->b_size = size; ! 220: ! 221: mb->b_next = (struct block *)NKMAGIC; ! 222: ! 223: } ! 224: ! 225: else { ! 226: ! 227: /* not big enough to cut: unlink this from free list */ ! 228: ! 229: NALLOC_DEBUG('w'); ! 230: ! 231: *q = mb->b_next; ! 232: ! 233: } ! 234: ! 235: return (void *)(mb+1); ! 236: ! 237: } ! 238: ! 239: } ! 240: ! 241: } ! 242: ! 243: ! 244: ! 245: /* no block available: get a new arena */ ! 246: ! 247: ! 248: ! 249: #if 1 ! 250: ! 251: return NULL; /* MiNT: fail. */ ! 252: ! 253: #else ! 254: ! 255: if (!minarena) { ! 256: ! 257: minarena = Malloc(-1L) / 20; ! 258: ! 259: if (minarena > MAXARENA) minarena = MAXARENA; ! 260: ! 261: } ! 262: ! 263: ! 264: ! 265: if (size < minarena) { ! 266: ! 267: NALLOC_DEBUG('m'); ! 268: ! 269: temp = minarena; ! 270: ! 271: } ! 272: ! 273: else { ! 274: ! 275: NALLOC_DEBUG('s'); ! 276: ! 277: temp = size; ! 278: ! 279: } ! 280: ! 281: ! 282: ! 283: a = (struct arena *)Malloc(temp + ! 284: ! 285: sizeof(struct arena) + ! 286: ! 287: sizeof(struct block)); ! 288: ! 289: ! 290: ! 291: /* if Malloc failed return failure */ ! 292: ! 293: if (a == 0) { ! 294: ! 295: NALLOC_DEBUG('x'); ! 296: ! 297: return 0; ! 298: ! 299: } ! 300: ! 301: ! 302: ! 303: a->a_size = temp + sizeof(struct block); ! 304: ! 305: a->a_next = a_first; ! 306: ! 307: a_first = a; ! 308: ! 309: mb = (struct block *)(a+1); ! 310: ! 311: mb->b_next = NULL; ! 312: ! 313: mb->b_size = size; ! 314: ! 315: ! 316: ! 317: if (temp > (size + sizeof(struct block))) { ! 318: ! 319: NALLOC_DEBUG('c'); ! 320: ! 321: b = a->a_ffirst = ((char *)(mb+1)) + size; ! 322: ! 323: b->b_next = NULL; ! 324: ! 325: b->b_size = temp - size - sizeof(struct block); ! 326: ! 327: } ! 328: ! 329: else { ! 330: ! 331: a->a_ffirst = NULL; ! 332: ! 333: } ! 334: ! 335: return (void *)(++mb); ! 336: ! 337: #endif ! 338: ! 339: } ! 340: ! 341: ! 342: ! 343: void ! 344: ! 345: nfree(start) ! 346: ! 347: void *start; ! 348: ! 349: { ! 350: ! 351: struct arena *a, **qa; ! 352: ! 353: struct block *b; ! 354: ! 355: struct block *pb; ! 356: ! 357: struct block *fb = (struct block *)start; ! 358: ! 359: ! 360: ! 361: NALLOC_DEBUG('F'); ! 362: ! 363: if (fb->b_next != (struct block *)NKMAGIC) { ! 364: ! 365: FATAL("nfree: block %lx not allocated by nalloc!",fb); ! 366: ! 367: } ! 368: ! 369: ! 370: ! 371: /* set fb (and b) to header start */ ! 372: ! 373: b = --fb; ! 374: ! 375: ! 376: ! 377: /* the arena this block lives in */ ! 378: ! 379: for (a = *(qa = &a_first); a; a = *(qa = &a->a_next)) { ! 380: ! 381: if ((unsigned long)b > (unsigned long)a && ! 382: ! 383: (unsigned long)b < (((unsigned long)a) + a->a_size)) goto found; ! 384: ! 385: } ! 386: ! 387: FATAL("nfree: block %lx not in any arena!",fb); ! 388: ! 389: ! 390: ! 391: found: ! 392: ! 393: /* Found it! */ ! 394: ! 395: /* a is this block's arena */ ! 396: ! 397: ! 398: ! 399: /* set pb to the previous free block in this arena, b to next */ ! 400: ! 401: for (pb = NULL, b = a->a_ffirst; ! 402: ! 403: b && (b < fb); ! 404: ! 405: pb = b, b = b->b_next) ; ! 406: ! 407: ! 408: ! 409: fb->b_next = b; ! 410: ! 411: ! 412: ! 413: /* Coalesce backwards: if any prev ... */ ! 414: ! 415: if (pb) { ! 416: ! 417: /* if it's adjacent ... */ ! 418: ! 419: if ((((unsigned long)(pb+1)) + pb->b_size) == (unsigned long)fb) { ! 420: ! 421: NALLOC_DEBUG('b'); ! 422: ! 423: pb->b_size += sizeof(struct block) + fb->b_size; ! 424: ! 425: fb = pb; ! 426: ! 427: } ! 428: ! 429: else { ! 430: ! 431: /* ... else not adjacent, but there is a prev free block */ ! 432: ! 433: /* so set its next ptr to fb */ ! 434: ! 435: pb->b_next = fb; ! 436: ! 437: } ! 438: ! 439: } ! 440: ! 441: else { ! 442: ! 443: /* ... else no prev free block: set arena's free list ptr to fb */ ! 444: ! 445: a->a_ffirst = fb; ! 446: ! 447: } ! 448: ! 449: ! 450: ! 451: /* Coalesce forwards: b holds start of free block AFTER fb, if any */ ! 452: ! 453: if (b && (((unsigned long)(fb+1)) + fb->b_size) == (unsigned long)b) { ! 454: ! 455: NALLOC_DEBUG('f'); ! 456: ! 457: fb->b_size += sizeof(struct block) + b->b_size; ! 458: ! 459: fb->b_next = b->b_next; ! 460: ! 461: } ! 462: ! 463: ! 464: ! 465: #if 0 ! 466: ! 467: /* if, after coalescing, this arena is entirely free, Mfree it! */ ! 468: ! 469: if (a->a_ffirst == a+1 && ! 470: ! 471: (a->a_ffirst->b_size + sizeof(struct block)) == a->a_size) { ! 472: ! 473: NALLOC_DEBUG('!'); ! 474: ! 475: *qa = a->a_next; ! 476: ! 477: (void)Mfree(a); ! 478: ! 479: } ! 480: ! 481: #endif ! 482: ! 483: ! 484: ! 485: return; ! 486: ! 487: } ! 488: ! 489: ! 490: ! 491: void ! 492: ! 493: NALLOC_DUMP() ! 494: ! 495: { ! 496: ! 497: struct arena *a; ! 498: ! 499: struct block *b; ! 500: ! 501: ! 502: ! 503: for (a = a_first; a; a = a->a_next) { ! 504: ! 505: FORCE("Arena at %lx size %lx: free list:",a,a->a_size); ! 506: ! 507: for (b = a->a_ffirst; b; b = b->b_next) { ! 508: ! 509: FORCE(" %8lx size %8lx",b,b->b_size); ! 510: ! 511: } ! 512: ! 513: } ! 514: ! 515: } ! 516:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.