]>
Commit | Line | Data |
---|---|---|
1 | #include <stdio.h> | |
2 | botch(message) | |
3 | char *message; | |
4 | { | |
5 | fprintf(stderr, "Malloc botch: %s\n", message); | |
6 | abort(); | |
7 | } | |
8 | ||
9 | #define rcheck | |
10 | /**************************************************************** | |
11 | * * | |
12 | * Storage Allocator for Foundation. * | |
13 | * Built from gnuemacs storage allocator * | |
14 | * * | |
15 | ****************************************************************/ | |
16 | ||
17 | /* Copyright (C) 1985 Richard M. Stallman, | |
18 | based mostly on the public domain work of others. | |
19 | ||
20 | This program is distributed in the hope that it will be useful, | |
21 | but without any warranty. No author or distributor | |
22 | accepts responsibility to anyone for the consequences of using it | |
23 | or for whether it serves any particular purpose or works at all, | |
24 | unless he says so in writing. | |
25 | ||
26 | Permission is granted to anyone to distribute verbatim copies | |
27 | of this program's source code as received, in any medium, provided that | |
28 | the copyright notice, the nonwarraty notice above | |
29 | and this permission notice are preserved, | |
30 | and that the distributor grants the recipient all rights | |
31 | for further redistribution as permitted by this notice, | |
32 | and informs him of these rights. | |
33 | ||
34 | Permission is granted to distribute modified versions of this | |
35 | program's source code, or of portions of it, under the above | |
36 | conditions, plus the conditions that all changed files carry | |
37 | prominent notices stating who last changed them and that the | |
38 | derived material, including anything packaged together with it and | |
39 | conceptually functioning as a modification of it rather than an | |
40 | application of it, is in its entirety subject to a permission | |
41 | notice identical to this one. | |
42 | ||
43 | Permission is granted to distribute this program (verbatim or | |
44 | as modified) in compiled or executable form, provided verbatim | |
45 | redistribution is permitted as stated above for source code, and | |
46 | A. it is accompanied by the corresponding machine-readable | |
47 | source code, under the above conditions, or | |
48 | B. it is accompanied by a written offer, with no time limit, | |
49 | to distribute the corresponding machine-readable source code, | |
50 | under the above conditions, to any one, in return for reimbursement | |
51 | of the cost of distribution. Verbatim redistribution of the | |
52 | written offer must be permitted. Or, | |
53 | C. it is distributed by someone who received only the | |
54 | compiled or executable form, and is accompanied by a copy of the | |
55 | written offer of source code which he received along with it. | |
56 | ||
57 | Permission is granted to distribute this program (verbatim or as modified) | |
58 | in executable form as part of a larger system provided that the source | |
59 | code for this program, including any modifications used, | |
60 | is also distributed or offered as stated in the preceding paragraph. | |
61 | ||
62 | In other words, you are welcome to use, share and improve this program. | |
63 | You are forbidden to forbid anyone else to use, share and improve | |
64 | what you give them. Help stamp out software-hoarding! */ | |
65 | \f | |
66 | /**************************************************************** | |
67 | * * | |
68 | * Helpful historical comments * | |
69 | * * | |
70 | ****************************************************************/ | |
71 | ||
72 | /* | |
73 | * @(#)nmalloc.c 1 (Caltech) 2/21/82 | |
74 | * | |
75 | * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs | |
76 | * | |
77 | * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. | |
78 | * | |
79 | * This is a very fast storage allocator. It allocates blocks of a small | |
80 | * number of different sizes, and keeps free lists of each size. Blocks | |
81 | * that don't exactly fit are passed up to the next larger size. In this | |
82 | * implementation, the available sizes are (2^n)-4 (or -16) bytes long. | |
83 | * This is designed for use in a program that uses vast quantities of | |
84 | * memory, but bombs when it runs out. To make it a little better, it | |
85 | * warns the user when he starts to get near the end. | |
86 | * | |
87 | * June 84, ACT: modified rcheck code to check the range given to malloc, | |
88 | * rather than the range determined by the 2-power used. | |
89 | * | |
90 | * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. | |
91 | * No longer Emacs-specific; can serve as all-purpose malloc for GNU. | |
92 | * You should call malloc_init to reinitialize after loading dumped Emacs. | |
93 | * Call malloc_stats to get info on memory stats if MSTATS turned on. | |
94 | * realloc knows how to return same block given, just changing its size, | |
95 | * if the power of 2 is correct. | |
96 | * | |
97 | * Jan 86, WDC: Removed Emacs specific stuff, and neatened a few comments. | |
98 | * | |
99 | * March 86 WDC: Added in code by Eichin for Scribble checking of blocks | |
100 | * Scribble check writes a known pattern into the free blocks, checks it | |
101 | * to see if it is still undamaged before allocating it. It writes a | |
102 | * different pattern into the space beyond the end of an allocated block, | |
103 | * and tests it for damage when expanding the block's bounds in realloc. | |
104 | * Note, this check takes *TIME* and should not be compiled in by default. | |
105 | * | |
106 | * Berkeley UNIX 4.3 has a storage allocator that shares a common | |
107 | * ancestor with this one. It handles realloc compatibly with the | |
108 | * archaic use of realloc on an already freed block to "compact" | |
109 | * storage. It uses a pagesize system call rather than assuming the | |
110 | * page size is 1024 bytes. Finally it guarantees that a freed block | |
111 | * is not munged by the allocator itself, incase someone wants to fiddle | |
112 | * with freed space after freeing it but before allocating more. | |
113 | * | |
114 | * This particular storage allocator would benefit from having a | |
115 | * non-hardwired pagesize. But because of the scribble check it would | |
116 | * not be useful to keep the free pointer in the header. SO: When you | |
117 | * free something allocated with this allocator, DONT TRY TO USE IT. | |
118 | * It is GUARANTEED to be damaged by the freeing process. | |
119 | * | |
120 | * For interfacing to systems that want to be able to ask the size of | |
121 | * the allocated block, rather than remembering it, the m_blocksize | |
122 | * function, rips open the block and tells you how big it is. The size | |
123 | * returned is nbytes, the number of bytes asked for, NOT the actual | |
124 | * amount of space in the block. | |
125 | */ | |
126 | \f | |
127 | /**************************************************************** | |
128 | * * | |
129 | * Includes, declarations, and definitions * | |
130 | * * | |
131 | ****************************************************************/ | |
132 | ||
133 | /* Determine which kind of system this is. */ | |
134 | #include <signal.h> | |
135 | #ifndef SIGTSTP | |
136 | #define USG | |
137 | #else /* SIGTSTP */ | |
138 | #ifdef SIGIO | |
139 | #define BSD42 | |
140 | #endif /* SIGIO */ | |
141 | #endif /* SIGTSTP */ | |
142 | ||
143 | #ifndef BSD42 | |
144 | #ifndef USG | |
145 | #include <sys/vlimit.h> /* warn the user when near the end */ | |
146 | #endif | |
147 | #else /* if BSD42 */ | |
148 | #include <sys/time.h> | |
149 | #include <sys/resource.h> | |
150 | #endif /* BSD42 */ | |
151 | ||
152 | #ifdef scribblecheck | |
153 | #define rcheck | |
154 | #endif /* we need to have range data to use block boundary checking */ | |
155 | ||
156 | #ifdef rcheck | |
157 | /* | |
158 | * To implement range checking, we write magic values in at the | |
159 | * beginning and end of each allocated block, and make sure they | |
160 | * are undisturbed whenever a free or a realloc occurs. | |
161 | */ | |
162 | ||
163 | /* Written in each of the 4 bytes following the block's real space */ | |
164 | #define MAGIC1 0x55 | |
165 | #define MAGICFREE 0x69 /* 0110 1001 Magic value for Free blocks */ | |
166 | ||
167 | /* Written in the 4 bytes before the block's real space */ | |
168 | #define MAGIC4 0x55555555 | |
169 | #define MAGICFREE4 0x69696969 | |
170 | ||
171 | #define ASSERT(p) if (!(p)) botch("p"); else | |
172 | #define EXTRA 4 /* 4 bytes extra for MAGIC1s */ | |
173 | #else | |
174 | #define ASSERT(p) | |
175 | #define EXTRA 0 | |
176 | #endif /* rcheck */ | |
177 | ||
178 | #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ | |
179 | #define ISFREE ((char) 0x54) /* magic byte that implies free block */ | |
180 | /* this is for error checking only */ | |
181 | ||
182 | /* If range checking is not turned on, all we have is a flag | |
183 | * indicating whether memory is allocated, an index in nextf[], | |
184 | * and a field that tells how many bytes. | |
185 | * To realloc() memory we copy nbytes. | |
186 | * 16 bits of header space is unused. | |
187 | */ | |
188 | struct mhead { | |
189 | char mh_alloc; /* ISALLOC or ISFREE */ | |
190 | char mh_index; /* index in nextf[] */ | |
191 | unsigned short mh_extra;/* Currently wasted 16 bits */ | |
192 | /* Remainder are valid only when block is allocated */ | |
193 | unsigned mh_nbytes; /* number of bytes allocated */ | |
194 | #ifdef rcheck | |
195 | int mh_magic4; /* should be == MAGIC4 */ | |
196 | #endif /* rcheck */ | |
197 | }; | |
198 | ||
199 | /* | |
200 | * Access free-list pointer of a block. | |
201 | * It is stored at block + 4. | |
202 | * This is not a field in the mhead structure because we want | |
203 | * sizeof (struct mhead) to describe the overhead for when the | |
204 | * block is in use, and we do not want the free-list pointer | |
205 | * to count in that. | |
206 | */ | |
207 | #define CHAIN(a) \ | |
208 | (*(struct mhead **) (sizeof (char *) + (char *) (a))) | |
209 | ||
210 | \f | |
211 | /**************************************************************** | |
212 | * * | |
213 | * Variable Creations * | |
214 | * * | |
215 | ****************************************************************/ | |
216 | ||
217 | extern char etext; | |
218 | extern char *start_of_data (); /* This seems necessary for USG */ | |
219 | ||
220 | #ifdef notdef | |
221 | ||
222 | /* These two are for user programs to look at, when they are interested. */ | |
223 | ||
224 | int malloc_sbrk_used; /* amount of data space used now */ | |
225 | int malloc_sbrk_unused; /* amount more we can have */ | |
226 | #endif notdef | |
227 | /* start of data space; can be changed by calling init_malloc */ | |
228 | static char *data_space_start; | |
229 | ||
230 | #ifdef MSTATS | |
231 | /* | |
232 | * nmalloc[i] is the difference between the number of mallocs and frees | |
233 | * for a given block size. | |
234 | */ | |
235 | static int nmalloc[30]; | |
236 | static int nmal, nfre; | |
237 | #endif /* MSTATS */ | |
238 | ||
239 | /* | |
240 | * nextf[i] is the pointer to the next free block of size 2^(i+3). The | |
241 | * smallest allocatable block is 8 bytes. The overhead information will | |
242 | * go in the first int of the block, and the returned pointer will point | |
243 | * to the second. | |
244 | */ | |
245 | static struct mhead *nextf[30]; | |
246 | ||
247 | /* Number of bytes of writable memory we can expect to be able to get */ | |
248 | static int lim_data; | |
249 | /* Level number of warnings already issued. | |
250 | * 0 -- no warnings issued. | |
251 | * 1 -- 75% warning already issued. | |
252 | * 2 -- 85% warning already issued. | |
253 | */ | |
254 | static int warnlevel; | |
255 | ||
256 | #ifdef notdef | |
257 | /* nonzero once initial bunch of free blocks made */ | |
258 | static int gotpool; | |
259 | #endif notdef | |
260 | \f | |
261 | /**************************************************************** | |
262 | * * | |
263 | * Start of procedures * | |
264 | * * | |
265 | * malloc_init, m_blocksize * | |
266 | * * | |
267 | ****************************************************************/ | |
268 | ||
269 | /* | |
270 | * Cause reinitialization based on job parameters; | |
271 | * also declare where the end of pure storage is. | |
272 | */ | |
273 | malloc_init (start) | |
274 | char *start; | |
275 | { | |
276 | data_space_start = start; | |
277 | lim_data = 0; | |
278 | warnlevel = 0; | |
279 | } | |
280 | ||
281 | int m_blocksize(a_block) | |
282 | char *a_block; | |
283 | { | |
284 | return(((struct mhead *)a_block-1)->mh_nbytes); | |
285 | } | |
286 | extern int MEinitLists(); | |
287 | ||
288 | static int (*foo)() = MEinitLists; | |
289 | ||
290 | \f | |
291 | /**************************************************************** | |
292 | * * | |
293 | * morecore - Ask the system for more memory * | |
294 | * * | |
295 | ****************************************************************/ | |
296 | ||
297 | static | |
298 | morecore (nu) /* ask system for more memory */ | |
299 | register int nu; /* size index to get more of */ | |
300 | { | |
301 | char *sbrk (); | |
302 | register char *cp; | |
303 | register int nblks; | |
304 | register int siz; | |
305 | ||
306 | #ifdef notdef | |
307 | if (!data_space_start) | |
308 | { | |
309 | #if defined(USG) | |
310 | data_space_start = start_of_data (); | |
311 | #else /* not USG */ | |
312 | data_space_start = &etext; | |
313 | #endif /* not USG */ | |
314 | } | |
315 | ||
316 | if (lim_data == 0) | |
317 | get_lim_data (); | |
318 | ||
319 | /* On initial startup, get two blocks of each size up to 1k bytes */ | |
320 | if (!gotpool) | |
321 | getpool (), getpool (), gotpool = 1; | |
322 | ||
323 | /* Find current end of memory and issue warning if getting near max */ | |
324 | ||
325 | cp = sbrk (0); | |
326 | siz = cp - data_space_start; | |
327 | malloc_sbrk_used = siz; | |
328 | malloc_sbrk_unused = lim_data - siz; | |
329 | ||
330 | switch (warnlevel) | |
331 | { | |
332 | case 0: | |
333 | if (siz > (lim_data / 4) * 3) | |
334 | { | |
335 | warnlevel++; | |
336 | malloc_warning ("Warning: past 75% of memory limit"); | |
337 | } | |
338 | break; | |
339 | case 1: | |
340 | if (siz > (lim_data / 20) * 17) | |
341 | { | |
342 | warnlevel++; | |
343 | malloc_warning ("Warning: past 85% of memory limit"); | |
344 | } | |
345 | break; | |
346 | case 2: | |
347 | if (siz > (lim_data / 20) * 19) | |
348 | { | |
349 | warnlevel++; | |
350 | malloc_warning ("Warning: past 95% of memory limit"); | |
351 | } | |
352 | break; | |
353 | } | |
354 | ||
355 | if ((int) cp & 0x3ff) /* land on 1K boundaries */ | |
356 | sbrk (1024 - ((int) cp & 0x3ff)); | |
357 | #endif notdef | |
358 | ||
359 | /* Take at least 2k, and figure out how many blocks of the desired size | |
360 | we're about to get */ | |
361 | nblks = 1; | |
362 | if ((siz = nu) < 8) | |
363 | nblks = 1 << ((siz = 8) - nu); | |
364 | #ifdef notdef | |
365 | if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) | |
366 | return; /* no more room! */ | |
367 | #endif notdef | |
368 | { | |
369 | char *tcp; | |
370 | if (MEalloc(1, 1 << (siz+3), &tcp)) | |
371 | return; /* No more room! */ | |
372 | cp = tcp; | |
373 | } | |
374 | if ((int) cp & 7) | |
375 | { /* shouldn't happen, but just in case */ | |
376 | cp = (char *) (((int) cp + 8) & ~7); | |
377 | nblks--; | |
378 | } | |
379 | ||
380 | /* save new header and link the nblks blocks together */ | |
381 | nextf[nu] = (struct mhead *) cp; | |
382 | siz = 1 << (nu + 3); | |
383 | while (1) | |
384 | { | |
385 | ((struct mhead *) cp) -> mh_alloc = ISFREE; | |
386 | ((struct mhead *) cp) -> mh_index = nu; | |
387 | #ifdef rcheck | |
388 | ((struct mhead *) cp) -> mh_magic4 = MAGICFREE4; | |
389 | #endif /* rcheck */ | |
390 | #ifdef scribblecheck | |
391 | { | |
392 | /* Check that upper stuff was still MAGIC1 */ | |
393 | register char *m = (char *)((struct mhead *)cp+1); | |
394 | register char *en = (8<<nu) + cp; | |
395 | /* Fill whole block with MAGICFREE */ | |
396 | while (m<en) *m++ = MAGICFREE; | |
397 | } | |
398 | #endif /* scribblecheck */ | |
399 | ||
400 | /* Clear newly allocated blocks, to match free ones */ | |
401 | if (--nblks <= 0) break; | |
402 | CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); | |
403 | cp += siz; | |
404 | } | |
405 | CHAIN ((struct mhead *) cp) = 0; | |
406 | } | |
407 | \f | |
408 | /**************************************************************** | |
409 | * * | |
410 | * getpool - Get initial pools of small blocks * | |
411 | * * | |
412 | ****************************************************************/ | |
413 | #ifdef notdef | |
414 | static | |
415 | getpool () | |
416 | { | |
417 | register int nu; | |
418 | register char *cp = sbrk (0); | |
419 | ||
420 | if ((int) cp & 0x3ff) /* land on 1K boundaries */ | |
421 | sbrk (1024 - ((int) cp & 0x3ff)); | |
422 | ||
423 | /* Get 2k of storage */ | |
424 | ||
425 | cp = sbrk (04000); | |
426 | if (cp == (char *) -1) | |
427 | return; | |
428 | ||
429 | /* Divide it into an initial 8-word block | |
430 | plus one block of size 2**nu for nu = 3 ... 10. */ | |
431 | ||
432 | CHAIN (cp) = nextf[0]; | |
433 | nextf[0] = (struct mhead *) cp; | |
434 | ((struct mhead *) cp) -> mh_alloc = ISFREE; | |
435 | ((struct mhead *) cp) -> mh_index = 0; | |
436 | #ifdef rcheck | |
437 | ((struct mhead *) cp) -> mh_magic4 = MAGICFREE4; | |
438 | #endif /* rcheck */ | |
439 | cp += 8; | |
440 | ||
441 | for (nu = 0; nu < 7; nu++) | |
442 | { | |
443 | CHAIN (cp) = nextf[nu]; | |
444 | nextf[nu] = (struct mhead *) cp; | |
445 | ((struct mhead *) cp) -> mh_alloc = ISFREE; | |
446 | ((struct mhead *) cp) -> mh_index = nu; | |
447 | #ifdef rcheck | |
448 | ((struct mhead *) cp) -> mh_magic4 = MAGICFREE4; | |
449 | #endif /* rcheck */ | |
450 | #ifdef scribblecheck | |
451 | { | |
452 | register char *m = (char *)((struct mhead *)cp+1); | |
453 | register char *en = (8<<nu) + cp; | |
454 | /* Fill whole block with MAGICFREE */ | |
455 | while (m<en) *m++ = MAGICFREE; | |
456 | } | |
457 | #endif /* scribblecheck */ | |
458 | cp += 8 << nu; | |
459 | } | |
460 | } | |
461 | #endif notdef | |
462 | \f | |
463 | /**************************************************************** | |
464 | * * | |
465 | * malloc - get a block of space from a pool * | |
466 | * * | |
467 | ****************************************************************/ | |
468 | ||
469 | char * | |
470 | malloc (n) /* get a block */ | |
471 | unsigned n; | |
472 | { | |
473 | register struct mhead *p; | |
474 | register unsigned int nbytes; | |
475 | register int nunits = 0; | |
476 | ||
477 | /* Figure out how many bytes are required, rounding up to the nearest | |
478 | multiple of 4, then figure out which nextf[] area to use */ | |
479 | nbytes = (n + sizeof *p + EXTRA + 3) & ~3; | |
480 | { | |
481 | register unsigned int shiftr = (nbytes - 1) >> 2; | |
482 | ||
483 | while (shiftr >>= 1) | |
484 | nunits++; | |
485 | } | |
486 | ||
487 | /* If there are no blocks of the appropriate size, go get some */ | |
488 | /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ | |
489 | if (nextf[nunits] == 0) | |
490 | morecore (nunits); | |
491 | ||
492 | /* Get one block off the list, and set the new list head */ | |
493 | if ((p = nextf[nunits]) == 0) | |
494 | return 0; | |
495 | nextf[nunits] = CHAIN (p); | |
496 | ||
497 | /* Check for free block clobbered */ | |
498 | /* If not for this check, we would gobble a clobbered free chain ptr */ | |
499 | /* and bomb out on the NEXT allocate of this size block */ | |
500 | if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) | |
501 | #ifdef rcheck | |
502 | botch ("block on free list clobbered"); | |
503 | #else /* not rcheck */ | |
504 | abort (); | |
505 | #endif /* not rcheck */ | |
506 | #ifdef rcheck | |
507 | if (p -> mh_magic4 != MAGICFREE4) | |
508 | botch ("Magic in block on free list clobbered"); | |
509 | #endif /* rcheck */ | |
510 | #ifdef scribblecheck | |
511 | /* Check for block filled with magic numbers, then change to zeros */ | |
512 | { | |
513 | register char *m = (char *) (p + 1); | |
514 | register char *en = (8<<p->mh_index) + (char *) p; | |
515 | register int block_valid = 0; | |
516 | while(m<en && (block_valid=(*m==MAGICFREE))) | |
517 | *m++=(char)0; | |
518 | /* so, status comes out as 1 if ok, 0 if terminated */ | |
519 | if (!block_valid) botch ("data on free list damaged"); | |
520 | } | |
521 | #endif /* scribblecheck */ | |
522 | /* Fill in the info, and if range checking, set up the magic numbers */ | |
523 | p -> mh_alloc = ISALLOC; | |
524 | p -> mh_nbytes = n; | |
525 | #ifdef rcheck | |
526 | p -> mh_magic4 = MAGIC4; | |
527 | { | |
528 | register char *m = (char *) (p + 1) + n; | |
529 | #ifdef scribblecheck | |
530 | register char *en = (8<<p->mh_index)+(char *)p; | |
531 | /* point to end of block */ | |
532 | while (m<en) *m++ = MAGIC1; | |
533 | #else /* scribblecheck */ | |
534 | *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; | |
535 | #endif /* scribblecheck */ | |
536 | } | |
537 | #endif /* not rcheck */ | |
538 | #ifdef MSTATS | |
539 | nmalloc[nunits]++; | |
540 | nmal++; | |
541 | #endif /* MSTATS */ | |
542 | return (char *) (p + 1); | |
543 | } | |
544 | \f | |
545 | /**************************************************************** | |
546 | * * | |
547 | * free - Free a block of space * | |
548 | * * | |
549 | ****************************************************************/ | |
550 | ||
551 | free (mem) | |
552 | char *mem; | |
553 | { | |
554 | register struct mhead *p; | |
555 | { | |
556 | register char *ap = mem; | |
557 | ||
558 | ASSERT (ap != 0); | |
559 | p = (struct mhead *) ap - 1; | |
560 | ASSERT (p -> mh_alloc == ISALLOC); | |
561 | #ifdef rcheck | |
562 | ASSERT (p -> mh_magic4 == MAGIC4); | |
563 | ap += p -> mh_nbytes; | |
564 | p->mh_magic4 = MAGICFREE4; | |
565 | ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); | |
566 | ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); | |
567 | #endif /* rcheck */ | |
568 | } | |
569 | { | |
570 | register int nunits = p -> mh_index; | |
571 | ||
572 | ASSERT (nunits <= 29); | |
573 | #ifdef scribblecheck | |
574 | { | |
575 | /* Check that upper stuff was still MAGIC1 */ | |
576 | register char *m = (char *) (p + 1) + p->mh_nbytes; | |
577 | register char *en = (8<<p->mh_index) + (char *) p; | |
578 | register int block_valid = 0; | |
579 | while(m<en && (block_valid=(*m++==MAGIC1))); | |
580 | if (!block_valid) botch ("block freed with data out of bounds"); | |
581 | /* Fill whole block with MAGICFREE */ | |
582 | m = (char *) (p + 1); | |
583 | while (m<en) *m++ = MAGICFREE; | |
584 | } | |
585 | #endif /* scribblecheck */ | |
586 | p -> mh_alloc = ISFREE; | |
587 | CHAIN (p) = nextf[nunits]; | |
588 | nextf[nunits] = p; | |
589 | #ifdef MSTATS | |
590 | nmalloc[nunits]--; | |
591 | nfre++; | |
592 | #endif /* MSTATS */ | |
593 | } | |
594 | } | |
595 | \f | |
596 | /**************************************************************** | |
597 | * * | |
598 | * realloc - resize a block, copy if necessary * | |
599 | * * | |
600 | ****************************************************************/ | |
601 | ||
602 | char * | |
603 | realloc (mem, n) | |
604 | char *mem; | |
605 | register unsigned n; | |
606 | { | |
607 | register struct mhead *p; | |
608 | register unsigned int tocopy; | |
609 | register int nbytes; | |
610 | register int nunits; | |
611 | ||
612 | if ((p = (struct mhead *) mem) == 0) | |
613 | return malloc (n); | |
614 | p--; | |
615 | nunits = p -> mh_index; | |
616 | ASSERT (p -> mh_alloc == ISALLOC); | |
617 | tocopy = p -> mh_nbytes; | |
618 | #ifdef rcheck | |
619 | ASSERT (p -> mh_magic4 == MAGIC4); | |
620 | { | |
621 | register char *m = mem + tocopy; | |
622 | #ifdef scribblecheck | |
623 | register char *en = (8<<p->mh_index) + (char *)p; | |
624 | register int block_valid = 0; | |
625 | while(m<en && (block_valid=(*m++==MAGIC1))); | |
626 | if (!block_valid) botch ("out of bounds data on realloc"); | |
627 | #else /* scribblecheck */ | |
628 | ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); | |
629 | ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); | |
630 | #endif /* scribblecheck */ | |
631 | } | |
632 | #endif /* not rcheck */ | |
633 | ||
634 | /* See if desired size rounds to same power of 2 as actual size. */ | |
635 | nbytes = (n + sizeof *p + EXTRA + 7) & ~7; | |
636 | ||
637 | /* If ok, use the same block, just marking its size as changed. */ | |
638 | if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) | |
639 | { | |
640 | /* Here we check on realloc if we are grabbing unused space */ | |
641 | #ifdef rcheck | |
642 | register char *m = mem + tocopy; | |
643 | #ifdef scribblecheck | |
644 | register char *en = (8<<p->mh_index) + (char *) p; | |
645 | while (m<en) *m++=(char)0; | |
646 | #else /* scribblecheck */ | |
647 | *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; | |
648 | #endif /* scribblecheck */ | |
649 | m = mem + n; | |
650 | #ifdef scribblecheck | |
651 | while(m<en) *m++ = MAGIC1; | |
652 | #else /* scribblecheck */ | |
653 | *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; | |
654 | #endif /* scribblecheck */ | |
655 | #endif /* not rcheck */ | |
656 | p-> mh_nbytes = n; | |
657 | return mem; | |
658 | } | |
659 | ||
660 | if (n < tocopy) | |
661 | tocopy = n; | |
662 | { | |
663 | register char *new; | |
664 | ||
665 | if ((new = malloc (n)) == 0) | |
666 | return 0; | |
667 | bcopy (mem, new, tocopy); | |
668 | free (mem); | |
669 | return new; | |
670 | } | |
671 | } | |
672 | \f | |
673 | /**************************************************************** | |
674 | * * | |
675 | * Memory Statistics stuff * | |
676 | * * | |
677 | ****************************************************************/ | |
678 | ||
679 | #ifdef MSTATS | |
680 | /* Return statistics describing allocation of blocks of size 2**n. */ | |
681 | ||
682 | struct mstats_value | |
683 | { | |
684 | int blocksize; | |
685 | int nfree; | |
686 | int nused; | |
687 | }; | |
688 | ||
689 | struct mstats_value | |
690 | malloc_stats (size) | |
691 | int size; | |
692 | { | |
693 | struct mstats_value v; | |
694 | register int i; | |
695 | register struct mhead *p; | |
696 | ||
697 | v.nfree = 0; | |
698 | ||
699 | if (size < 0 || size >= 30) | |
700 | { | |
701 | v.blocksize = 0; | |
702 | v.nused = 0; | |
703 | return v; | |
704 | } | |
705 | ||
706 | v.blocksize = 1 << (size + 3); | |
707 | v.nused = nmalloc[size]; | |
708 | ||
709 | for (p = nextf[size]; p; p = CHAIN (p)) | |
710 | v.nfree++; | |
711 | ||
712 | return v; | |
713 | } | |
714 | #endif /* MSTATS */ | |
715 | \f | |
716 | #ifdef notdef | |
717 | /**************************************************************** | |
718 | * * | |
719 | * Stuff having to do with determining memory limits * | |
720 | * * | |
721 | ****************************************************************/ | |
722 | ||
723 | /* | |
724 | * This function returns the total number of bytes that the process | |
725 | * will be allowed to allocate via the sbrk(2) system call. On | |
726 | * BSD systems this is the total space allocatable to stack and | |
727 | * data. On USG systems this is the data space only. | |
728 | */ | |
729 | ||
730 | #ifdef USG | |
731 | ||
732 | get_lim_data () | |
733 | { | |
734 | extern long ulimit (); | |
735 | ||
736 | lim_data = ulimit (3, 0); | |
737 | lim_data -= (long) data_space_start; | |
738 | } | |
739 | ||
740 | #else /* not USG */ | |
741 | #ifndef BSD42 | |
742 | ||
743 | get_lim_data () | |
744 | { | |
745 | lim_data = vlimit (LIM_DATA, -1); | |
746 | } | |
747 | ||
748 | #else /* BSD42 */ | |
749 | ||
750 | get_lim_data () | |
751 | { | |
752 | struct rlimit XXrlimit; | |
753 | ||
754 | getrlimit (RLIMIT_DATA, &XXrlimit); | |
755 | lim_data = XXrlimit.rlim_cur; /* soft limit */ | |
756 | } | |
757 | ||
758 | #endif /* BSD42 */ | |
759 | #endif /* not USG */ | |
760 | #endif notdef | |
761 | ||
762 | /* | |
763 | * Calloc - allocate and clear memory block | |
764 | */ | |
765 | char * | |
766 | calloc(num, size) | |
767 | register unsigned num, size; | |
768 | { | |
769 | extern char *malloc(); | |
770 | register char *p; | |
771 | ||
772 | size *= num; | |
773 | if (p = malloc(size)) | |
774 | bzero(p, size); | |
775 | return (p); | |
776 | } | |
777 | ||
778 | cfree(p, num, size) | |
779 | char *p; | |
780 | unsigned num; | |
781 | unsigned size; | |
782 | { | |
783 | free(p); | |
784 | } |