home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1992 Atari Corporation.
- * All rights reserved.
- */
-
- #include "mint.h"
-
- /* macro for testing whether a memory region is free */
- #define ISFREE(m) ((m)->links == 0)
-
- /*
- * long
- * realloc_region(MEMREGION *reg, long newsize):
- * attempt to resize "reg" to the indicated size. If newsize is
- * less than the current region size, the call always
- * succeeds; otherwise, we look for free blocks next to the
- * region, and try to merge these.
- *
- * If newsize == -1L, simply returns the maximum size that
- * the block could be allocated to.
- *
- * Returns: the (physical) address of the new bottom of the
- * region, or 0L if the resize attempt fails.
- *
- * NOTES: if reg == 0, this call does a last-fit allocation
- * of memory of the requested size, and returns a MEMREGION *
- * (cast to a long) pointing at the last region that works
- *
- * This call works ONLY in the "core" memory region (aka ST RAM)
- * and only on non-shared text regions.
- */
-
- long
- realloc_region(reg, newsize)
- MEMREGION *reg;
- long newsize;
- {
- MMAP map;
- MEMREGION *m,*prevptr;
- long oldsize, trysize;
-
- if (newsize != -1L)
- newsize = ROUND(newsize);
- oldsize = reg->len;
-
- if ( reg == 0 || (reg->mflags & M_CORE))
- map = core;
- else {
- return 0;
- }
-
- /* last fit allocation: this is pretty straightforward,
- * we just look for the last block that would work
- * and slice off the top part of it.
- * problem: we don't know what the "last block that would fit"
- * is for newsize == -1L, so we look for the biggest block
- */
- if (reg == 0) {
- MEMREGION *lastfit = 0;
- MEMREGION *newm = new_region();
-
- for (m = *map; m; m = m->next) {
- if (ISFREE(m)) {
- if (newsize == -1L && lastfit
- && m->len >= lastfit->len)
- lastfit = m;
- else if (m->len >= newsize)
- lastfit = m;
- }
- }
- if (!lastfit)
- return 0;
-
- if (newsize == -1L)
- return lastfit->len;
-
- /* if the sizes match exactly, we save a bit of work */
- if (lastfit->len == newsize) {
- if (newm) dispose_region(newm);
- lastfit->links++;
- mark_region(lastfit, PROT_G);
- return (long)lastfit;
- }
- if (!newm) return 0; /* can't get a new region */
-
- /* chop off the top "newsize" bytes from lastfit */
- /* and add it to "newm" */
- lastfit->len -= newsize;
- newm->loc = lastfit->loc + lastfit->len;
- newm->len = newsize;
- newm->mflags = lastfit->mflags & M_MAP;
- newm->links++;
- newm->next = lastfit->next;
- lastfit->next = newm;
- mark_region(newm, PROT_G);
- return (long)newm;
- }
-
- /* check for trivial resize */
- if (newsize == oldsize) {
- return reg->loc;
- }
-
- /*
- * find the block just before ours
- */
- if (*map == reg)
- prevptr = 0;
- else {
- prevptr = *map;
- while (prevptr->next != reg && prevptr) {
- prevptr = prevptr->next;
- }
- }
- /*
- * If we're shrinking the block, there's not too much to
- * do (we just free the first "oldsize-newsize" bytes by
- * creating a new region, putting those bytes into it,
- * and freeing it).
- */
- if (newsize < oldsize && newsize != -1L) {
-
- if (prevptr && ISFREE(prevptr)) {
- /* add this memory to the previous free region */
- prevptr->len += oldsize - newsize;
- reg->loc += oldsize - newsize;
- reg->len -= oldsize - newsize;
- mark_region(prevptr, PROT_I);
- mark_region(reg, PROT_G);
- return reg->loc;
- }
-
- /* make a new region for the freed memory */
- m = new_region();
- if (!m) {
- /* oops, couldn't get a region -- we lose */
- /* punt and pretend we succeeded; after all,
- * we have enough memory!
- */
- return reg->loc;
- }
-
- /* set up the fake region */
- m->links = 0;
- m->mflags = reg->mflags & M_MAP;
- m->loc = reg->loc;
- m->len = oldsize - newsize;
- /* update our region (it's smaller now) */
- reg->loc += m->len;
- reg->len -= m->len;
- /* link the region in just ahead of us */
- if (prevptr)
- prevptr->next = m;
- else
- *map = m;
- m->next = reg;
- mark_region(m, PROT_I);
- mark_region(reg, PROT_G);
- return reg->loc;
- }
-
- /* OK, here we have to grow the region: to do this, we first try adding
- * bytes from the region after us (if any) and then the region before
- * us
- */
- trysize = oldsize;
- if (reg->next && ISFREE(reg->next) &&
- (reg->loc + reg->len == reg->next->loc)) {
- trysize += reg->next->len;
- }
- if (prevptr && ISFREE(prevptr) &&
- (prevptr->loc + prevptr->len == reg->loc)) {
- trysize += prevptr->len;
- }
- if (trysize < newsize) {
- FORCE("realloc_region: need %ld bytes, only have %ld", trysize, newsize);
- return 0; /* not enough room */
- }
-
- if (newsize == -1L) /* size inquiry only?? */
- return trysize;
-
- /* BUG: we can be a bit too aggressive at sweeping up
- * memory regions coming after our region; on the other
- * hand, unless something goes seriously wrong there
- * never should *be* any such regions
- */
- if (reg->next && ISFREE(reg->next) &&
- (reg->loc + reg->len == reg->next->loc)) {
- MEMREGION *foo = reg->next;
-
- reg->len += foo->len;
- reg->next = foo->next;
- dispose_region(foo);
- mark_region(reg, PROT_G);
- if (reg->len >= newsize)
- return reg->loc;
- oldsize = reg->len;
- }
- assert(prevptr && ISFREE(prevptr) &&
- prevptr->loc + prevptr->len == reg->loc);
-
- if (newsize > oldsize) {
- reg->loc -= (newsize - oldsize);
- reg->len += (newsize - oldsize);
- prevptr->len -= (newsize - oldsize);
- if (prevptr->len == 0) {
- /* hmmm, we used up the whole region -- we must dispose of the
- * region descriptor
- */
- if (*map == prevptr)
- *map = prevptr->next;
- else {
- for (m = *map; m; m = m->next) {
- if (m->next == prevptr) {
- m->next = prevptr->next;
- break;
- }
- }
- }
- dispose_region(prevptr);
- }
- mark_region(reg, PROT_G);
- }
-
- /* finally! we return the new starting address of "our" region */
- return reg->loc;
- }
-
-
-
- /*
- * s_realloc emulation: this isn't quite perfect, since the memory
- * used up by the "first" screen will be wasted (we could recover
- * this if we knew the screen start and size, and manually built
- * a region for that screen and linked it into the "core" map
- * (probably at the end))
- * We must always ensure a 256 byte "pad" area is available after
- * the screen (so that it doesn't abut the end of memory)
- */
-
- MEMREGION *screen_region = 0;
-
- #define PAD 256L
-
- long ARGS_ON_STACK
- s_realloc(size)
- long size;
- {
- long r;
-
- TRACE(("s_realloc(%ld)", size));
-
- if (size != -1L)
- size += PAD;
-
- if (!screen_region) {
- r = realloc_region(screen_region, size);
- if (size == -1L) { /* inquiry only */
- TRACE(("%ld bytes max srealloc", r-PAD));
- return r - PAD;
- }
- screen_region = (MEMREGION *)r;
- if (!screen_region) {
- DEBUG(("s_realloc: no screen region!!"));
- return 0;
- }
- return screen_region->loc;
- }
- r = realloc_region(screen_region, size);
- if (size == -1L) {
- return r - PAD;
- } else {
- return r;
- }
- }
-