|
|
1.1 root 1: /* dynamic memory allocation for GNU.
2: Copyright (C) 1985, 1987 Free Software Foundation, Inc.
3:
4: This program is free software; you can redistribute it and/or modify
5: it under the terms of the GNU General Public License as published by
6: the Free Software Foundation; either version 1, or (at your option)
7: any later version.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17:
18: In other words, you are welcome to use, share and improve this program.
19: You are forbidden to forbid anyone else to use, share and improve
20: what you give them. Help stamp out software-hoarding! */
21:
22:
23: /*
24: * @(#)nmalloc.c 1 (Caltech) 2/21/82
25: *
26: * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs
27: *
28: * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD.
29: *
30: * This is a very fast storage allocator. It allocates blocks of a small
31: * number of different sizes, and keeps free lists of each size. Blocks
32: * that don't exactly fit are passed up to the next larger size. In this
33: * implementation, the available sizes are (2^n)-4 (or -16) bytes long.
34: * This is designed for use in a program that uses vast quantities of
35: * memory, but bombs when it runs out. To make it a little better, it
36: * warns the user when he starts to get near the end.
37: *
38: * June 84, ACT: modified rcheck code to check the range given to malloc,
39: * rather than the range determined by the 2-power used.
40: *
41: * Jan 85, RMS: calls malloc_warning to issue warning on nearly full.
42: * No longer Emacs-specific; can serve as all-purpose malloc for GNU.
43: * You should call malloc_init to reinitialize after loading dumped Emacs.
44: * Call malloc_stats to get info on memory stats if MSTATS turned on.
45: * realloc knows how to return same block given, just changing its size,
46: * if the power of 2 is correct.
47: */
48:
49: /*
50: * nextf[i] is the pointer to the next free block of size 2^(i+3). The
51: * smallest allocatable block is 8 bytes. The overhead information will
52: * go in the first int of the block, and the returned pointer will point
53: * to the second.
54: *
55: #ifdef MSTATS
56: * nmalloc[i] is the difference between the number of mallocs and frees
57: * for a given block size.
58: #endif MSTATS
59: */
60:
61: #ifdef emacs
62: /* config.h specifies which kind of system this is. */
63: #include "config.h"
64:
65: /* This must precede sys/signal.h on certain machines. */
66: #include <sys/types.h>
67: #include <signal.h>
68: #else
69:
70: /* Determine which kind of system this is. */
71: /* This must precede sys/signal.h on certain machines. */
72: #include <sys/types.h>
73: #include <signal.h>
74: #ifndef SIGTSTP
75: #ifndef VMS
76: #ifndef USG
77: #define USG
78: #endif
79: #endif /* not VMS */
80: #else /* SIGTSTP */
81: #ifdef SIGIO
82: #define BSD4_2
83: #endif /* SIGIO */
84: #endif /* SIGTSTP */
85:
86: #endif /* not emacs */
87:
88: /* Define getpagesize () if the system does not. */
89: #include "getpagesize.h"
90:
91: #ifdef BSD
92: #ifdef BSD4_1
93: #include <sys/vlimit.h> /* warn the user when near the end */
94: #else /* if 4.2 or newer */
95: #include <sys/time.h>
96: #include <sys/resource.h>
97: #endif /* if 4.2 or newer */
98: #endif
99:
100: #ifdef VMS
101: #include "vlimit.h"
102: #endif
103:
104: extern char *start_of_data ();
105:
106: #ifdef BSD
107: #ifndef DATA_SEG_BITS
108: #define start_of_data() &etext
109: #endif
110: #endif
111:
112: #ifndef emacs
113: #define start_of_data() &etext
114: #endif
115:
116: #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
117: #define ISFREE ((char) 0x54) /* magic byte that implies free block */
118: /* this is for error checking only */
119: #define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by
120: memalign, with the rest of the word
121: being the distance to the true
122: beginning of the block. */
123:
124: extern char etext;
125:
126: /* These two are for user programs to look at, when they are interested. */
127:
128: unsigned int malloc_sbrk_used; /* amount of data space used now */
129: unsigned int malloc_sbrk_unused; /* amount more we can have */
130:
131: /* start of data space; can be changed by calling init_malloc */
132: static char *data_space_start;
133:
134: #ifdef MSTATS
135: static int nmalloc[30];
136: static int nmal, nfre;
137: #endif /* MSTATS */
138:
139: /* If range checking is not turned on, all we have is a flag indicating
140: whether memory is allocated, an index in nextf[], and a size field; to
141: realloc() memory we copy either size bytes or 1<<(index+3) bytes depending
142: on whether the former can hold the exact size (given the value of
143: 'index'). If range checking is on, we always need to know how much space
144: is allocated, so the 'size' field is never used. */
145:
146: struct mhead {
147: char mh_alloc; /* ISALLOC or ISFREE */
148: char mh_index; /* index in nextf[] */
149: /* Remainder are valid only when block is allocated */
150: unsigned short mh_size; /* size, if < 0x10000 */
151: #ifdef rcheck
152: unsigned mh_nbytes; /* number of bytes allocated */
153: int mh_magic4; /* should be == MAGIC4 */
154: #endif /* rcheck */
155: };
156:
157: /* Access free-list pointer of a block.
158: It is stored at block + 4.
159: This is not a field in the mhead structure
160: because we want sizeof (struct mhead)
161: to describe the overhead for when the block is in use,
162: and we do not want the free-list pointer to count in that. */
163:
164: #define CHAIN(a) \
165: (*(struct mhead **) (sizeof (char *) + (char *) (a)))
166:
167: #ifdef rcheck
168:
169: /* To implement range checking, we write magic values in at the beginning and
170: end of each allocated block, and make sure they are undisturbed whenever a
171: free or a realloc occurs. */
172: /* Written in each of the 4 bytes following the block's real space */
173: #define MAGIC1 0x55
174: /* Written in the 4 bytes before the block's real space */
175: #define MAGIC4 0x55555555
176: #define ASSERT(p) if (!(p)) botch("p"); else
177: #define EXTRA 4 /* 4 bytes extra for MAGIC1s */
178: #else
179: #define ASSERT(p) if (!(p)) abort (); else
180: #define EXTRA 0
181: #endif /* rcheck */
182:
183:
184: /* nextf[i] is free list of blocks of size 2**(i + 3) */
185:
186: static struct mhead *nextf[30];
187:
188: /* busy[i] is nonzero while allocation of block size i is in progress. */
189:
190: static char busy[30];
191:
192: /* Number of bytes of writable memory we can expect to be able to get */
193: static unsigned int lim_data;
194:
195: /* Level number of warnings already issued.
196: 0 -- no warnings issued.
197: 1 -- 75% warning already issued.
198: 2 -- 85% warning already issued.
199: */
200: static int warnlevel;
201:
202: /* Function to call to issue a warning;
203: 0 means don't issue them. */
204: static void (*warnfunction) ();
205:
206: /* nonzero once initial bunch of free blocks made */
207: static int gotpool;
208:
209: char *_malloc_base;
210:
211: static void getpool ();
212:
213: char *malloc ();
214:
215: /* Cause reinitialization based on job parameters;
216: also declare where the end of pure storage is. */
217: void
218: malloc_init (start, warnfun)
219: char *start;
220: void (*warnfun) ();
221: {
222: if (start)
223: data_space_start = start;
224: lim_data = 0;
225: warnlevel = 0;
226: warnfunction = warnfun;
227: }
228:
229: /* Return the maximum size to which MEM can be realloc'd
230: without actually requiring copying. */
231:
232: int
233: malloc_usable_size (mem)
234: char *mem;
235: {
236: struct mhead *p
237: = (struct mhead *) (mem - ((sizeof (struct mhead) + 7) & ~7));
238: int blocksize = 8 << p->mh_index;
239:
240: return blocksize - sizeof (struct mhead) - EXTRA;
241: }
242:
243: static void
244: morecore (nu) /* ask system for more memory */
245: register int nu; /* size index to get more of */
246: {
247: char *sbrk ();
248: register char *cp;
249: register int nblks;
250: register unsigned int siz;
251: int oldmask;
252:
253: #ifdef BSD
254: #ifndef BSD4_1
255: int newmask = -1;
256: /* Blocking these signals interferes with debugging, at least on BSD on
257: the HP 9000/300. */
258: #ifdef SIGTRAP
259: newmask &= ~(1 << SIGTRAP);
260: #endif
261: #ifdef SIGILL
262: newmask &= ~(1 << SIGILL);
263: #endif
264: #ifdef SIGTSTP
265: newmask &= ~(1 << SIGTSTP);
266: #endif
267: #ifdef SIGSTOP
268: newmask &= ~(1 << SIGSTOP);
269: #endif
270: oldmask = sigsetmask (newmask);
271: #endif
272: #endif
273:
274: if (!data_space_start)
275: {
276: data_space_start = start_of_data ();
277: }
278:
279: if (lim_data == 0)
280: get_lim_data ();
281:
282: /* On initial startup, get two blocks of each size up to 1k bytes */
283: if (!gotpool)
284: { getpool (); getpool (); gotpool = 1; }
285:
286: /* Find current end of memory and issue warning if getting near max */
287:
288: #ifndef VMS
289: /* Maximum virtual memory on VMS is difficult to calculate since it
290: * depends on several dynmacially changing things. Also, alignment
291: * isn't that important. That is why much of the code here is ifdef'ed
292: * out for VMS systems.
293: */
294: cp = sbrk (0);
295: siz = cp - data_space_start;
296:
297: if (warnfunction)
298: switch (warnlevel)
299: {
300: case 0:
301: if (siz > (lim_data / 4) * 3)
302: {
303: warnlevel++;
304: (*warnfunction) ("Warning: past 75% of memory limit");
305: }
306: break;
307: case 1:
308: if (siz > (lim_data / 20) * 17)
309: {
310: warnlevel++;
311: (*warnfunction) ("Warning: past 85% of memory limit");
312: }
313: break;
314: case 2:
315: if (siz > (lim_data / 20) * 19)
316: {
317: warnlevel++;
318: (*warnfunction) ("Warning: past 95% of memory limit");
319: }
320: break;
321: }
322:
323: if ((int) cp & 0x3ff) /* land on 1K boundaries */
324: sbrk (1024 - ((int) cp & 0x3ff));
325: #endif /* not VMS */
326:
327: /* Take at least 2k, and figure out how many blocks of the desired size
328: we're about to get */
329: nblks = 1;
330: if ((siz = nu) < 8)
331: nblks = 1 << ((siz = 8) - nu);
332:
333: if ((cp = sbrk (1 << (siz + 3))) == (char *) -1)
334: {
335: #ifdef BSD
336: #ifndef BSD4_1
337: sigsetmask (oldmask);
338: #endif
339: #endif
340: return; /* no more room! */
341: }
342: malloc_sbrk_used = siz;
343: malloc_sbrk_unused = lim_data - siz;
344:
345: #ifndef VMS
346: if ((int) cp & 7)
347: { /* shouldn't happen, but just in case */
348: cp = (char *) (((int) cp + 8) & ~7);
349: nblks--;
350: }
351: #endif /* not VMS */
352:
353: /* save new header and link the nblks blocks together */
354: nextf[nu] = (struct mhead *) cp;
355: siz = 1 << (nu + 3);
356: while (1)
357: {
358: ((struct mhead *) cp) -> mh_alloc = ISFREE;
359: ((struct mhead *) cp) -> mh_index = nu;
360: if (--nblks <= 0) break;
361: CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
362: cp += siz;
363: }
364: CHAIN ((struct mhead *) cp) = 0;
365:
366: #ifdef BSD
367: #ifndef BSD4_1
368: sigsetmask (oldmask);
369: #endif
370: #endif
371: }
372:
373: static void
374: getpool ()
375: {
376: register int nu;
377: char * sbrk ();
378: register char *cp = sbrk (0);
379:
380: if ((int) cp & 0x3ff) /* land on 1K boundaries */
381: sbrk (1024 - ((int) cp & 0x3ff));
382:
383: /* Record address of start of space allocated by malloc. */
384: if (_malloc_base == 0)
385: _malloc_base = cp;
386:
387: /* Get 2k of storage */
388:
389: cp = sbrk (04000);
390: if (cp == (char *) -1)
391: return;
392:
393: /* Divide it into an initial 8-word block
394: plus one block of size 2**nu for nu = 3 ... 10. */
395:
396: CHAIN (cp) = nextf[0];
397: nextf[0] = (struct mhead *) cp;
398: ((struct mhead *) cp) -> mh_alloc = ISFREE;
399: ((struct mhead *) cp) -> mh_index = 0;
400: cp += 8;
401:
402: for (nu = 0; nu < 7; nu++)
403: {
404: CHAIN (cp) = nextf[nu];
405: nextf[nu] = (struct mhead *) cp;
406: ((struct mhead *) cp) -> mh_alloc = ISFREE;
407: ((struct mhead *) cp) -> mh_index = nu;
408: cp += 8 << nu;
409: }
410: }
411:
412: char *
413: malloc (n) /* get a block */
414: unsigned n;
415: {
416: register struct mhead *p;
417: register unsigned int nbytes;
418: register int nunits = 0;
419:
420: /* Figure out how many bytes are required, rounding up to the nearest
421: multiple of 8, then figure out which nestf[] area to use.
422: Both the beginning of the header and the beginning of the
423: block should be on an eight byte boundary. */
424: #ifdef SUNOS_LOCALTIME_BUG
425: if (n < 16)
426: n = 16;
427: #endif
428: nbytes = (n + ((sizeof *p + 7) & ~7) + EXTRA + 7) & ~7;
429: {
430: register unsigned int shiftr = (nbytes - 1) >> 2;
431:
432: while (shiftr >>= 1)
433: nunits++;
434: }
435:
436: /* In case this is reentrant use of malloc from signal handler,
437: pick a block size that no other malloc level is currently
438: trying to allocate. That's the easiest harmless way not to
439: interfere with the other level of execution. */
440: while (busy[nunits]) nunits++;
441: busy[nunits] = 1;
442:
443: /* If there are no blocks of the appropriate size, go get some */
444: /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
445: if (nextf[nunits] == 0)
446: morecore (nunits);
447:
448: /* Get one block off the list, and set the new list head */
449: if ((p = nextf[nunits]) == 0)
450: {
451: busy[nunits] = 0;
452: return 0;
453: }
454: nextf[nunits] = CHAIN (p);
455: busy[nunits] = 0;
456:
457: /* Check for free block clobbered */
458: /* If not for this check, we would gobble a clobbered free chain ptr */
459: /* and bomb out on the NEXT allocate of this size block */
460: if (p -> mh_alloc != ISFREE || p -> mh_index != nunits)
461: #ifdef rcheck
462: botch ("block on free list clobbered");
463: #else /* not rcheck */
464: abort ();
465: #endif /* not rcheck */
466:
467: /* Fill in the info, and if range checking, set up the magic numbers */
468: p -> mh_alloc = ISALLOC;
469: #ifdef rcheck
470: p -> mh_nbytes = n;
471: p -> mh_magic4 = MAGIC4;
472: {
473: /* Get the location n after the beginning of the user's space. */
474: register char *m = (char *) p + ((sizeof *p + 7) & ~7) + n;
475:
476: *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
477: }
478: #else /* not rcheck */
479: p -> mh_size = n;
480: #endif /* not rcheck */
481: #ifdef MSTATS
482: nmalloc[nunits]++;
483: nmal++;
484: #endif /* MSTATS */
485: return (char *) p + ((sizeof *p + 7) & ~7);
486: }
487:
488: free (mem)
489: char *mem;
490: {
491: register struct mhead *p;
492: {
493: register char *ap = mem;
494:
495: if (ap == 0)
496: return;
497:
498: p = (struct mhead *) (ap - ((sizeof *p + 7) & ~7));
499: if (p -> mh_alloc == ISMEMALIGN)
500: {
501: ap -= p->mh_size;
502: p = (struct mhead *) (ap - ((sizeof *p + 7) & ~7));
503: }
504:
505: #ifndef rcheck
506: if (p -> mh_alloc != ISALLOC)
507: abort ();
508:
509: #else rcheck
510: if (p -> mh_alloc != ISALLOC)
511: {
512: if (p -> mh_alloc == ISFREE)
513: botch ("free: Called with already freed block argument\n");
514: else
515: botch ("free: Called with bad argument\n");
516: }
517:
518: ASSERT (p -> mh_magic4 == MAGIC4);
519: ap += p -> mh_nbytes;
520: ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
521: ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1);
522: #endif /* rcheck */
523: }
524: {
525: register int nunits = p -> mh_index;
526:
527: ASSERT (nunits <= 29);
528: p -> mh_alloc = ISFREE;
529:
530: /* Protect against signal handlers calling malloc. */
531: busy[nunits] = 1;
532: /* Put this block on the free list. */
533: CHAIN (p) = nextf[nunits];
534: nextf[nunits] = p;
535: busy[nunits] = 0;
536:
537: #ifdef MSTATS
538: nmalloc[nunits]--;
539: nfre++;
540: #endif /* MSTATS */
541: }
542: }
543:
544: char *
545: realloc (mem, n)
546: char *mem;
547: register unsigned n;
548: {
549: register struct mhead *p;
550: register unsigned int tocopy;
551: register unsigned int nbytes;
552: register int nunits;
553:
554: if (mem == 0)
555: return malloc (n);
556: p = (struct mhead *) (mem - ((sizeof *p + 7) & ~7));
557: nunits = p -> mh_index;
558: ASSERT (p -> mh_alloc == ISALLOC);
559: #ifdef rcheck
560: ASSERT (p -> mh_magic4 == MAGIC4);
561: {
562: register char *m = mem + (tocopy = p -> mh_nbytes);
563: ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
564: ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1);
565: }
566: #else /* not rcheck */
567: if (p -> mh_index >= 13)
568: tocopy = (1 << (p -> mh_index + 3)) - ((sizeof *p + 7) & ~7);
569: else
570: tocopy = p -> mh_size;
571: #endif /* not rcheck */
572:
573: /* See if desired size rounds to same power of 2 as actual size. */
574: nbytes = (n + ((sizeof *p + 7) & ~7) + EXTRA + 7) & ~7;
575:
576: /* If ok, use the same block, just marking its size as changed. */
577: if (nbytes > (4 << nunits) && nbytes <= (8 << nunits))
578: {
579: #ifdef rcheck
580: register char *m = mem + tocopy;
581: *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
582: p-> mh_nbytes = n;
583: m = mem + n;
584: *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1;
585: #else /* not rcheck */
586: p -> mh_size = n;
587: #endif /* not rcheck */
588: return mem;
589: }
590:
591: if (n < tocopy)
592: tocopy = n;
593: {
594: register char *new;
595:
596: if ((new = malloc (n)) == 0)
597: return 0;
598: bcopy (mem, new, tocopy);
599: free (mem);
600: return new;
601: }
602: }
603:
604: /* This is in case something linked with Emacs calls calloc. */
605:
606: char *
607: calloc (num, size)
608: unsigned num, size;
609: {
610: register char *mem;
611:
612: num *= size;
613: mem = malloc (num);
614: if (mem != 0)
615: bzero (mem, num);
616: return mem;
617: }
618:
619: /* This is in case something linked with Emacs calls cfree. */
620:
621: cfree (mem)
622: char *mem;
623: {
624: return free (mem);
625: }
626:
627: #ifndef VMS
628:
629: char *
630: memalign (alignment, size)
631: unsigned alignment, size;
632: {
633: register char *ptr = malloc (size + alignment);
634: register char *aligned;
635: register struct mhead *p;
636:
637: if (ptr == 0)
638: return 0;
639: /* If entire block has the desired alignment, just accept it. */
640: if (((int) ptr & (alignment - 1)) == 0)
641: return ptr;
642: /* Otherwise, get address of byte in the block that has that alignment. */
643: aligned = (char *) (((int) ptr + alignment - 1) & -alignment);
644:
645: /* Store a suitable indication of how to free the block,
646: so that free can find the true beginning of it. */
647: p = (struct mhead *) (aligned - ((7 + sizeof (struct mhead)) & ~7));
648: p -> mh_size = aligned - ptr;
649: p -> mh_alloc = ISMEMALIGN;
650: return aligned;
651: }
652:
653: #ifndef HPUX
654: /* This runs into trouble with getpagesize on HPUX.
655: Patching out seems cleaner than the ugly fix needed. */
656: char *
657: valloc (size)
658: {
659: return memalign (getpagesize (), size);
660: }
661: #endif /* not HPUX */
662: #endif /* not VMS */
663:
664: #ifdef MSTATS
665: /* Return statistics describing allocation of blocks of size 2**n. */
666:
667: struct mstats_value
668: {
669: int blocksize;
670: int nfree;
671: int nused;
672: };
673:
674: struct mstats_value
675: malloc_stats (size)
676: int size;
677: {
678: struct mstats_value v;
679: register int i;
680: register struct mhead *p;
681:
682: v.nfree = 0;
683:
684: if (size < 0 || size >= 30)
685: {
686: v.blocksize = 0;
687: v.nused = 0;
688: return v;
689: }
690:
691: v.blocksize = 1 << (size + 3);
692: v.nused = nmalloc[size];
693:
694: for (p = nextf[size]; p; p = CHAIN (p))
695: v.nfree++;
696:
697: return v;
698: }
699: int
700: malloc_mem_used ()
701: {
702: int i;
703: int size_used;
704:
705: size_used = 0;
706:
707: for (i = 0; i < 30; i++)
708: {
709: int allocation_size = 1 << (i + 3);
710: struct mhead *p;
711:
712: size_used += nmalloc[i] * allocation_size;
713: }
714:
715: return size_used;
716: }
717:
718: int
719: malloc_mem_free ()
720: {
721: int i;
722: int size_unused;
723:
724: size_unused = 0;
725:
726: for (i = 0; i < 30; i++)
727: {
728: int allocation_size = 1 << (i + 3);
729: struct mhead *p;
730:
731: for (p = nextf[i]; p ; p = CHAIN (p))
732: size_unused += allocation_size;
733: }
734:
735: return size_unused;
736: }
737: #endif /* MSTATS */
738:
739: /*
740: * This function returns the total number of bytes that the process
741: * will be allowed to allocate via the sbrk(2) system call. On
742: * BSD systems this is the total space allocatable to stack and
743: * data. On USG systems this is the data space only.
744: */
745:
746: #ifdef USG
747:
748: get_lim_data ()
749: {
750: extern long ulimit ();
751:
752: #ifdef ULIMIT_BREAK_VALUE
753: lim_data = ULIMIT_BREAK_VALUE;
754: #else
755: lim_data = ulimit (3, 0);
756: #endif
757:
758: lim_data -= (long) data_space_start;
759: }
760:
761: #else /* not USG */
762: #if defined (BSD4_1) || defined (VMS)
763:
764: get_lim_data ()
765: {
766: lim_data = vlimit (LIM_DATA, -1);
767: }
768:
769: #else /* not BSD4_1 and not VMS */
770:
771: get_lim_data ()
772: {
773: struct rlimit XXrlimit;
774:
775: getrlimit (RLIMIT_DATA, &XXrlimit);
776: #ifdef RLIM_INFINITY
777: lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */
778: #else
779: lim_data = XXrlimit.rlim_cur; /* soft limit */
780: #endif
781: }
782:
783: #endif /* not BSD4_1 and not VMS */
784: #endif /* not USG */
785:
786: #ifdef VMS
787: /* There is a problem when dumping and restoring things on VMS. Calls
788: * to SBRK don't necessarily result in contiguous allocation. Dumping
789: * doesn't work when it isn't. Therefore, we make the initial
790: * allocation contiguous by allocating a big chunk, and do SBRKs from
791: * there. Once Emacs has dumped there is no reason to continue
792: * contiguous allocation, malloc doesn't depend on it.
793: *
794: * There is a further problem of using brk and sbrk while using VMS C
795: * run time library routines malloc, calloc, etc. The documentation
796: * says that this is a no-no, although I'm not sure why this would be
797: * a problem. In any case, we remove the necessity to call brk and
798: * sbrk, by calling calloc (to assure zero filled data) rather than
799: * sbrk.
800: *
801: * VMS_ALLOCATION_SIZE is the size of the allocation array. This
802: * should be larger than the malloc size before dumping. Making this
803: * too large will result in the startup procedure slowing down since
804: * it will require more space and time to map it in.
805: *
806: * The value for VMS_ALLOCATION_SIZE in the following define was determined
807: * by running emacs linked (and a large allocation) with the debugger and
808: * looking to see how much storage was used. The allocation was 201 pages,
809: * so I rounded it up to a power of two.
810: */
811: #ifndef VMS_ALLOCATION_SIZE
812: #define VMS_ALLOCATION_SIZE (512*256)
813: #endif
814:
815: /* Use VMS RTL definitions */
816: #undef sbrk
817: #undef brk
818: #undef malloc
819: int vms_out_initial = 0;
820: char vms_initial_buffer[VMS_ALLOCATION_SIZE];
821: static char *vms_current_brk = vms_initial_buffer;
822: static char *vms_end_brk = &vms_initial_buffer[VMS_ALLOCATION_SIZE-1];
823:
824: #include <stdio.h>
825:
826: char *
827: sys_sbrk (incr)
828: int incr;
829: {
830: char *sbrk(), *temp, *ptr;
831:
832: if (vms_out_initial)
833: {
834: /* out of initial allocation... */
835: if (!(temp = (char*) malloc (incr)))
836: temp = (char *) -1;
837: }
838: else
839: {
840: /* otherwise, go out of our area */
841: ptr = vms_current_brk + incr; /* new current_brk */
842: if (ptr <= vms_end_brk)
843: {
844: temp = vms_current_brk;
845: vms_current_brk = ptr;
846: }
847: else
848: {
849: vms_out_initial = 1; /* mark as out of initial allocation */
850: if (!(temp = (char*) malloc (incr)))
851: temp = (char *) -1;
852: }
853: }
854: return temp;
855: }
856: #endif /* VMS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.