|
|
1.1 ! root 1: /* ! 2: ! 3: * Copyright 1992 Atari Corporation. ! 4: ! 5: * All rights reserved. ! 6: ! 7: */ ! 8: ! 9: ! 10: ! 11: #include "mint.h" ! 12: ! 13: ! 14: ! 15: /* macro for testing whether a memory region is free */ ! 16: ! 17: #define ISFREE(m) ((m)->links == 0) ! 18: ! 19: ! 20: ! 21: /* ! 22: ! 23: * long ! 24: ! 25: * realloc_region(MEMREGION *reg, long newsize): ! 26: ! 27: * attempt to resize "reg" to the indicated size. If newsize is ! 28: ! 29: * less than the current region size, the call always ! 30: ! 31: * succeeds; otherwise, we look for free blocks next to the ! 32: ! 33: * region, and try to merge these. ! 34: ! 35: * ! 36: ! 37: * If newsize == -1L, simply returns the maximum size that ! 38: ! 39: * the block could be allocated to. ! 40: ! 41: * ! 42: ! 43: * Returns: the (physical) address of the new bottom of the ! 44: ! 45: * region, or 0L if the resize attempt fails. ! 46: ! 47: * ! 48: ! 49: * NOTES: if reg == 0, this call does a last-fit allocation ! 50: ! 51: * of memory of the requested size, and returns a MEMREGION * ! 52: ! 53: * (cast to a long) pointing at the last region that works ! 54: ! 55: * ! 56: ! 57: * This call works ONLY in the "core" memory region (aka ST RAM) ! 58: ! 59: * and only on non-shared text regions. ! 60: ! 61: */ ! 62: ! 63: ! 64: ! 65: long ! 66: ! 67: realloc_region(reg, newsize) ! 68: ! 69: MEMREGION *reg; ! 70: ! 71: long newsize; ! 72: ! 73: { ! 74: ! 75: MMAP map; ! 76: ! 77: MEMREGION *m,*prevptr; ! 78: ! 79: long oldsize, trysize; ! 80: ! 81: ! 82: ! 83: if (newsize != -1L) ! 84: ! 85: newsize = ROUND(newsize); ! 86: ! 87: oldsize = reg->len; ! 88: ! 89: ! 90: ! 91: if ( reg == 0 || (reg->mflags & M_CORE)) ! 92: ! 93: map = core; ! 94: ! 95: else { ! 96: ! 97: return 0; ! 98: ! 99: } ! 100: ! 101: ! 102: ! 103: /* last fit allocation: this is pretty straightforward, ! 104: ! 105: * we just look for the last block that would work ! 106: ! 107: * and slice off the top part of it. ! 108: ! 109: * problem: we don't know what the "last block that would fit" ! 110: ! 111: * is for newsize == -1L, so we look for the biggest block ! 112: ! 113: */ ! 114: ! 115: if (reg == 0) { ! 116: ! 117: MEMREGION *lastfit = 0; ! 118: ! 119: MEMREGION *newm = new_region(); ! 120: ! 121: ! 122: ! 123: for (m = *map; m; m = m->next) { ! 124: ! 125: if (ISFREE(m)) { ! 126: ! 127: if (newsize == -1L && lastfit ! 128: ! 129: && m->len >= lastfit->len) ! 130: ! 131: lastfit = m; ! 132: ! 133: else if (m->len >= newsize) ! 134: ! 135: lastfit = m; ! 136: ! 137: } ! 138: ! 139: } ! 140: ! 141: if (!lastfit) ! 142: ! 143: return 0; ! 144: ! 145: ! 146: ! 147: if (newsize == -1L) ! 148: ! 149: return lastfit->len; ! 150: ! 151: ! 152: ! 153: /* if the sizes match exactly, we save a bit of work */ ! 154: ! 155: if (lastfit->len == newsize) { ! 156: ! 157: if (newm) dispose_region(newm); ! 158: ! 159: lastfit->links++; ! 160: ! 161: mark_region(lastfit, PROT_G); ! 162: ! 163: return (long)lastfit; ! 164: ! 165: } ! 166: ! 167: if (!newm) return 0; /* can't get a new region */ ! 168: ! 169: ! 170: ! 171: /* chop off the top "newsize" bytes from lastfit */ ! 172: ! 173: /* and add it to "newm" */ ! 174: ! 175: lastfit->len -= newsize; ! 176: ! 177: newm->loc = lastfit->loc + lastfit->len; ! 178: ! 179: newm->len = newsize; ! 180: ! 181: newm->mflags = lastfit->mflags & M_MAP; ! 182: ! 183: newm->links++; ! 184: ! 185: newm->next = lastfit->next; ! 186: ! 187: lastfit->next = newm; ! 188: ! 189: mark_region(newm, PROT_G); ! 190: ! 191: return (long)newm; ! 192: ! 193: } ! 194: ! 195: ! 196: ! 197: /* check for trivial resize */ ! 198: ! 199: if (newsize == oldsize) { ! 200: ! 201: return reg->loc; ! 202: ! 203: } ! 204: ! 205: ! 206: ! 207: /* ! 208: ! 209: * find the block just before ours ! 210: ! 211: */ ! 212: ! 213: if (*map == reg) ! 214: ! 215: prevptr = 0; ! 216: ! 217: else { ! 218: ! 219: prevptr = *map; ! 220: ! 221: while (prevptr->next != reg && prevptr) { ! 222: ! 223: prevptr = prevptr->next; ! 224: ! 225: } ! 226: ! 227: } ! 228: ! 229: /* ! 230: ! 231: * If we're shrinking the block, there's not too much to ! 232: ! 233: * do (we just free the first "oldsize-newsize" bytes by ! 234: ! 235: * creating a new region, putting those bytes into it, ! 236: ! 237: * and freeing it). ! 238: ! 239: */ ! 240: ! 241: if (newsize < oldsize && newsize != -1L) { ! 242: ! 243: ! 244: ! 245: if (prevptr && ISFREE(prevptr)) { ! 246: ! 247: /* add this memory to the previous free region */ ! 248: ! 249: prevptr->len += oldsize - newsize; ! 250: ! 251: reg->loc += oldsize - newsize; ! 252: ! 253: reg->len -= oldsize - newsize; ! 254: ! 255: mark_region(prevptr, PROT_I); ! 256: ! 257: mark_region(reg, PROT_G); ! 258: ! 259: return reg->loc; ! 260: ! 261: } ! 262: ! 263: ! 264: ! 265: /* make a new region for the freed memory */ ! 266: ! 267: m = new_region(); ! 268: ! 269: if (!m) { ! 270: ! 271: /* oops, couldn't get a region -- we lose */ ! 272: ! 273: /* punt and pretend we succeeded; after all, ! 274: ! 275: * we have enough memory! ! 276: ! 277: */ ! 278: ! 279: return reg->loc; ! 280: ! 281: } ! 282: ! 283: ! 284: ! 285: /* set up the fake region */ ! 286: ! 287: m->links = 0; ! 288: ! 289: m->mflags = reg->mflags & M_MAP; ! 290: ! 291: m->loc = reg->loc; ! 292: ! 293: m->len = oldsize - newsize; ! 294: ! 295: /* update our region (it's smaller now) */ ! 296: ! 297: reg->loc += m->len; ! 298: ! 299: reg->len -= m->len; ! 300: ! 301: /* link the region in just ahead of us */ ! 302: ! 303: if (prevptr) ! 304: ! 305: prevptr->next = m; ! 306: ! 307: else ! 308: ! 309: *map = m; ! 310: ! 311: m->next = reg; ! 312: ! 313: mark_region(m, PROT_I); ! 314: ! 315: mark_region(reg, PROT_G); ! 316: ! 317: return reg->loc; ! 318: ! 319: } ! 320: ! 321: ! 322: ! 323: /* OK, here we have to grow the region: to do this, we first try adding ! 324: ! 325: * bytes from the region after us (if any) and then the region before ! 326: ! 327: * us ! 328: ! 329: */ ! 330: ! 331: trysize = oldsize; ! 332: ! 333: if (reg->next && ISFREE(reg->next) && ! 334: ! 335: (reg->loc + reg->len == reg->next->loc)) { ! 336: ! 337: trysize += reg->next->len; ! 338: ! 339: } ! 340: ! 341: if (prevptr && ISFREE(prevptr) && ! 342: ! 343: (prevptr->loc + prevptr->len == reg->loc)) { ! 344: ! 345: trysize += prevptr->len; ! 346: ! 347: } ! 348: ! 349: if (trysize < newsize) { ! 350: ! 351: FORCE("realloc_region: need %ld bytes, only have %ld", trysize, newsize); ! 352: ! 353: return 0; /* not enough room */ ! 354: ! 355: } ! 356: ! 357: ! 358: ! 359: if (newsize == -1L) /* size inquiry only?? */ ! 360: ! 361: return trysize; ! 362: ! 363: ! 364: ! 365: /* BUG: we can be a bit too aggressive at sweeping up ! 366: ! 367: * memory regions coming after our region; on the other ! 368: ! 369: * hand, unless something goes seriously wrong there ! 370: ! 371: * never should *be* any such regions ! 372: ! 373: */ ! 374: ! 375: if (reg->next && ISFREE(reg->next) && ! 376: ! 377: (reg->loc + reg->len == reg->next->loc)) { ! 378: ! 379: MEMREGION *foo = reg->next; ! 380: ! 381: ! 382: ! 383: reg->len += foo->len; ! 384: ! 385: reg->next = foo->next; ! 386: ! 387: dispose_region(foo); ! 388: ! 389: mark_region(reg, PROT_G); ! 390: ! 391: if (reg->len >= newsize) ! 392: ! 393: return reg->loc; ! 394: ! 395: oldsize = reg->len; ! 396: ! 397: } ! 398: ! 399: assert(prevptr && ISFREE(prevptr) && ! 400: ! 401: prevptr->loc + prevptr->len == reg->loc); ! 402: ! 403: ! 404: ! 405: if (newsize > oldsize) { ! 406: ! 407: reg->loc -= (newsize - oldsize); ! 408: ! 409: reg->len += (newsize - oldsize); ! 410: ! 411: prevptr->len -= (newsize - oldsize); ! 412: ! 413: if (prevptr->len == 0) { ! 414: ! 415: /* hmmm, we used up the whole region -- we must dispose of the ! 416: ! 417: * region descriptor ! 418: ! 419: */ ! 420: ! 421: if (*map == prevptr) ! 422: ! 423: *map = prevptr->next; ! 424: ! 425: else { ! 426: ! 427: for (m = *map; m; m = m->next) { ! 428: ! 429: if (m->next == prevptr) { ! 430: ! 431: m->next = prevptr->next; ! 432: ! 433: break; ! 434: ! 435: } ! 436: ! 437: } ! 438: ! 439: } ! 440: ! 441: dispose_region(prevptr); ! 442: ! 443: } ! 444: ! 445: mark_region(reg, PROT_G); ! 446: ! 447: } ! 448: ! 449: ! 450: ! 451: /* finally! we return the new starting address of "our" region */ ! 452: ! 453: return reg->loc; ! 454: ! 455: } ! 456: ! 457: ! 458: ! 459: ! 460: ! 461: ! 462: ! 463: /* ! 464: ! 465: * s_realloc emulation: this isn't quite perfect, since the memory ! 466: ! 467: * used up by the "first" screen will be wasted (we could recover ! 468: ! 469: * this if we knew the screen start and size, and manually built ! 470: ! 471: * a region for that screen and linked it into the "core" map ! 472: ! 473: * (probably at the end)) ! 474: ! 475: * We must always ensure a 256 byte "pad" area is available after ! 476: ! 477: * the screen (so that it doesn't abut the end of memory) ! 478: ! 479: */ ! 480: ! 481: ! 482: ! 483: MEMREGION *screen_region = 0; ! 484: ! 485: ! 486: ! 487: #define PAD 256L ! 488: ! 489: ! 490: ! 491: long ARGS_ON_STACK ! 492: ! 493: s_realloc(size) ! 494: ! 495: long size; ! 496: ! 497: { ! 498: ! 499: long r; ! 500: ! 501: ! 502: ! 503: TRACE(("s_realloc(%ld)", size)); ! 504: ! 505: ! 506: ! 507: if (size != -1L) ! 508: ! 509: size += PAD; ! 510: ! 511: ! 512: ! 513: if (!screen_region) { ! 514: ! 515: r = realloc_region(screen_region, size); ! 516: ! 517: if (size == -1L) { /* inquiry only */ ! 518: ! 519: TRACE(("%ld bytes max srealloc", r-PAD)); ! 520: ! 521: return r - PAD; ! 522: ! 523: } ! 524: ! 525: screen_region = (MEMREGION *)r; ! 526: ! 527: if (!screen_region) { ! 528: ! 529: DEBUG(("s_realloc: no screen region!!")); ! 530: ! 531: return 0; ! 532: ! 533: } ! 534: ! 535: return screen_region->loc; ! 536: ! 537: } ! 538: ! 539: r = realloc_region(screen_region, size); ! 540: ! 541: if (size == -1L) { ! 542: ! 543: return r - PAD; ! 544: ! 545: } else { ! 546: ! 547: return r; ! 548: ! 549: } ! 550: ! 551: } ! 552:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.