|
|
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.