1 /* $XConsortium: t1malloc.c,v 1.5 93/09/10 10:48:21 rws Exp $ */
2 /* Copyright International Business Machines, Corp. 1991
4 * Copyright Lexmark International, Inc. 1991
7 * License to use, copy, modify, and distribute this software and its
8 * documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and that
10 * both that copyright notice and this permission notice appear in
11 * supporting documentation, and that the name of IBM or Lexmark not be
12 * used in advertising or publicity pertaining to distribution of the
13 * software without specific, written prior permission.
15 * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
16 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
17 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
18 * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
19 * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
20 * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
21 * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
22 * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
23 * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
24 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
25 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
26 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
29 /* MALLOC CWEB V0004 LOTS */
31 :h1.MALLOC - Fast Memory Allocation
33 This module is meant to provide portable C-style memory allocation
34 routines (malloc/free).
36 &author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
40 #include "objects.h" /* get #define for abort() */
43 static freeuncombinable();
49 In the beginning, C compilers made no assumptions about NULL. It was
50 even theoretically possible that NULL would not be 0. ANSI has tied
51 this down a bit. The following definition seems to be the most
52 popular (in terms of reducing compiler complaints), however, if your
53 compiler is unhappy about it, you can redefine it on the command line:
59 Of course, NULL is important because xiMalloc() is defined to return
60 NULL when out of memory.
62 :h2.Data Structures Used to Manage Free Memory
64 :h3.The "freeblock" Structure
66 The list of available memory blocks is a doubly-linked list. Each
67 block begins with the following structure:
71 long size; /* number of 'longs' in block,
72 including this header */
73 struct freeblock *fore; /* forward in doubly-linked list */
74 struct freeblock *back; /* backward in doubly-linked list */
77 In addition, each free block has a TRAILER that is simply the 'size'
78 repeated. Thus 'size' is found at the beginning of the block and at the
79 end of the block (size-1 longs away). 'size' includes both the header
82 When a block is allocated, its 'size' is turned negative (both at the
83 beginning and at the end). Thus, checking whether two blocks may be
84 combined is very simple. We merely examine both neighboring blocks'
85 size to see if they are positive (and hence available for combination).
87 The memory address returned to the user is therefore one "long" below the
88 size, and one extra "long" is added to the end of the block (beyond what
89 the user requested) to store the trailing size.
91 :h3."firstfree" and "lastfree", the Anchors to the Free List
93 "firstfree" points to the first available free block; "lastfree" points
94 to the end of the chain of available blocks. These are linked together
95 by initialization code; see :hdref refid=addmem..
98 static struct freeblock firstfree = { 0L, NULL, NULL };
99 static struct freeblock lastfree = { 0L, NULL, NULL };
102 :h3."firstcombined" and "uncombined", Keeping Track of Uncombined Blocks
104 This module is designed to make the combining of adjacent free memory
105 blocks be very fast. Nonetheless, combining blocks is naturally the
106 most expensive part of any memory system. In an X system,
107 it is worthwhile to defer the combination for a while, because
108 frequently we will end up asking for a block of exactly the same
109 size that we recently returned and we can save ourselves some work.
111 "MAXUNCOMBINED" is the maximum number of uncombined blocks that we will
115 #define MAXUNCOMBINED 3
118 "firstcombined" is a pointer into the free list. The uncombined blocks
119 are always at the front of the list. "firstcombined" points to the
120 first block that has been combined.
122 static struct freeblock *firstcombined = &lastfree;
123 static short uncombined = 0; /* current number of uncombined blocks */
126 Uncombined blocks have a negative 'size'; in this they are like
129 We store a distinctive hex pattern in 'size' when we combine a block
132 #define COMBINED 0xBADBAD
135 :h3.DEBUGWORDS - Extra Memory Saved With Each Block for Debug
137 We add 'DEBUGWORDS' words to each allocated block to put interesting
145 :h3.MINEXCESS - Amount of "Excess" We Would be Willing to Ignore
147 When we search the free list to find memory for a user request, we
148 frequently find an area that is bigger than what the user has asked for.
149 Normally we put the remaining words (the excess) back on the free list.
150 However, if the area is just slightly bigger than what the user needs,
151 it is counter-productive to do this, as the small amount recovered tends
152 to hurt by increasing memory fragmentation rather than help by providing
153 more available memory. "MINEXCESS" is the number of words that must be
154 recovered before we would bother to put the excess back on the free
155 list. If there is not enough excess, we just give the user more than he
159 #define MINEXCESS (7 + DEBUGWORDS)
162 :h3.Some Flags for Debug
165 long AvailableWords = 0; /* number of words available in memory */
166 char mallocdebug = 0; /* a flag that enables some chatty printf's */
169 :h3.whocalledme() - Debug for Memory Leaks
171 This routine is 68000-specific; it copies the value of the application's
172 curOper variable (which is often a pointer to a character string), and
173 the first part of the stack at the time malloc was called into the
174 DEBUGWORDS area reserved with each block.
175 We use it to see who is malloc-ing memory without free-ing it.
180 static whocalledme(addr, stack)
181 long *addr; /* address of memory block */
182 long *stack; /* address of malloc's parameter on stack */
184 register long size; /* size of memory block */
185 register int i; /* loop index */
186 extern char *curOper; /* ptr to last operator (kept by appl.) */
191 addr += size - 1 - DEBUGWORDS;
192 *addr++ = (long) curOper;
193 for (i=0; i < DEBUGWORDS-1; i++)
198 #define whocalledme(addr, stack)
202 :h2.xiFree() - User-Callable "Return Memory" Routine
204 The actual beginning of the block is one 'long' before the address we
205 gave to the user. The block begins and ends with '-size' in words.
209 register long *addr; /* user's memory to be returned */
211 register long size; /* amount of memory in this block */
212 register struct freeblock *p; /* identical to 'addr' */
214 if (addr == NULL) { /* common "mistake", so allow it (CHT) */
215 printf("\nxiFree(NULL)?\n");
221 Make sure this address looks OK; 'size' must be less than zero (meaning
222 the block is allocated) and should be repeated at the end of the block.
225 abort("free: bad size");
226 if (addr[-1 - size] != size)
227 abort("free: mismatched size");
229 Now make this a 'freeblock' structure and tack it on the FRONT of the
230 free list (where uncombined blocks go):
232 AvailableWords -= size; /* actually INCREASES AvailableWords */
233 p = (struct freeblock *) addr;
234 p->back = &firstfree;
235 (p->fore = firstfree.fore)->back = p;
238 If we have too many uncombined blocks, call combine() to combine one.
240 if (++uncombined > MAXUNCOMBINED) {
243 printf("xiFree(%08x) with combine, ", addr);
249 printf("xiFree(%08x), ", addr);
258 :h3.combine() - Subroutine of xiFree() to Combine Blocks
260 This routine tries to combine the block just before 'firstcombined'.
261 In any event, that block will be moved to the end of the list (after
267 register struct freeblock *p; /* block we will try to combine */
268 register long *addr; /* identical to 'p' for 'long' access */
269 register long size; /* size of this block */
270 register long size2; /* size of potential combinee */
272 p = firstcombined->back;
274 abort("why are we combining?");
278 if (--uncombined < 0)
279 abort("too many combine()s");
281 if (addr[-1] < 0 && addr[size] < 0) {
283 We special case the situation where no combining can be done. Then, we
284 just mark the chain "combined" (i.e., positive size), move the
285 'firstcombined' pointer back in the chain, and return.
287 addr[0] = addr[size - 1] = size;
288 firstcombined = (struct freeblock *) addr;
292 Otherwise, we unhook this pointer from the chain:
296 First we attempt to combine this with the block immediately above:
299 if (size2 > 0) { /* i.e., block above is free */
300 *addr = COMBINED; /* might help debug */
302 if (addr[0] != size2)
303 abort("bad block above");
308 At this point 'addr' and 'size' may be the original block, or it may be
309 the newly combined block. Now we attempt to combine it with the block
312 p = (struct freeblock *) (addr + size);
315 if (size2 > 0) { /* i.e., block below is free */
317 if (size2 != ((long *) p)[size2 - 1])
318 abort("bad block below");
323 Finally we take the newly combined block and put it on the end of the
324 chain by calling the "freeuncombinable" subroutine:
326 freeuncombinable(addr, size);
330 :h3.freeuncombinable() - Free a Block That Need Not be Combined
332 This block is "uncombinable" either because we have already combined
333 it with its eligible neighbors, or perhaps because we know it has
337 static freeuncombinable(addr, size)
338 register long *addr; /* address of the block to be freed */
339 register long size; /* size of block in words */
341 register struct freeblock *p; /* a convenient synonym for 'addr' */
344 Mark block allocated and combined by setting its 'size' positive:
346 addr[size - 1] = addr[0] = size;
348 Now tack the block on the end of the doubly-linked free list:
350 p = (struct freeblock *) addr;
352 (p->back = lastfree.back)->fore = p;
355 If we have previously had no combined blocks, we must update
356 'firstcombined' to point to this block:
358 if (firstcombined->fore == NULL)
363 :h3.unhook() - Unhook a Block from the Doubly-linked List
365 The only tricky thing here is to make sure that 'firstcombined' is
366 updated if this block happened to be the old 'firstcombined'. (We
367 would never be unhooking 'firstfree' or 'lastfree', so we do not
368 have to worry about the end cases.)
372 register struct freeblock *p; /* block to unhook */
374 p->back->fore = p->fore;
375 p->fore->back = p->back;
377 if (firstcombined == p)
378 firstcombined = p->fore;
381 :h2.xiMalloc() - Main User Entry Point for Getting Memory
383 We have two slightly different versions of xiMalloc(). In the case
384 where we have TYPE1IMAGER and a font cache, we are prepared, when nominally
385 out of memory, to loop calling TYPE1IMAGER's GimeSpace() to release font
389 /* The following code put in by MDC on 11/10/90 */
393 static char *malloc_local();
396 register unsigned size;
400 while ( (memaddr = malloc_local(size)) == NULL ) {
401 /* Ask TYPE1IMAGER to give us some of its cache back */
402 if ( I_GimeSpace() == 0 ) break; /* We are really, really, out of memory */
410 Now begins the real workhorse xiMalloc() (called 'malloc_local' if
411 we are taking advantage of TYPE1IMAGER). Its argument is an unsigned;
412 at least that lets users with 16-bit integers get a 64K chunk of
413 memory, and it is also compatible with the definition of a "size_t"
417 static char *malloc_local(Size)
421 unsigned Size; /* number of bytes the user requested */
423 register long size = (long)Size; /* a working register for size */
424 register struct freeblock *p; /* tentative block to be returned */
425 register long excess; /* words in excess of user request */
426 register long *area; /* a convenient synonym for 'p' */
429 First, we increase 'size' to allow for the two size fields we will
430 save with the block, plus any information for debug purposes.
431 Then we ensure that the block will be large enough to hold our
432 'freeblock' information. Finally we convert it to be in words
433 (longs), not bytes, increased to span an integral number of double
434 words, so that all memory blocks dispensed with be properly aligned.
436 size += 2*sizeof(long) + DEBUGWORDS*sizeof(long);
437 if (size < sizeof(struct freeblock) + sizeof(long))
438 size = sizeof(struct freeblock) + sizeof(long);
439 size = ((unsigned) (size + sizeof(double) - 1) / sizeof(double)) * (sizeof(double)/sizeof(long));
442 For speed, we will try first to give the user back a very recently
443 returned block--one that is on the front of the chain before
444 'firstcombined'. These blocks still have negative sizes, and need
445 only to be "unhook"ed:
448 for (p=firstfree.fore; p != firstcombined; p=p->fore) {
449 if (p->size == size) {
453 printf("fast xiMalloc(%d) = %08x, ", size, p);
456 AvailableWords += size; /* decreases AvailableWords */
457 whocalledme(p, &Size);
458 return((char *)&p->fore);
462 Well, if we get here, there are no uncombined blocks matching the user's
463 request. So, we search the rest of the chain for a block that is big
464 enough. ('size' becomes positive again):
467 for (;; p = p->fore) {
469 If we hit the end of the chain (p->size == 0), we are probably out of
470 memory. However, we should first try to combine any memory that has
471 not yet been combined before we give that pessimistic answer. If
472 we succeed in combining, we can call ourselves recursively to try to
473 allocate the requested amount:
478 while (firstfree.fore != firstcombined)
480 return(xiMalloc(sizeof(long) * (size - 2 - DEBUGWORDS)));
483 Otherwise, we keep searching until we find a big enough block:
489 At this point, 'p' contains a block at least as big as what the user
490 requested, so we take it off the free chain. If it is excessively big,
491 we return the excess to the free chain:
494 excess = p->size - size;
497 if (excess > MINEXCESS)
498 freeuncombinable(area + size, excess);
502 AvailableWords -= size;
504 Mark first and last word of block with the negative of the size, to
505 flag that this block is allocated:
507 area[size - 1] = area[0] = - size;
510 printf("slow xiMalloc(%d) @ %08x, ", size, area);
513 whocalledme(area, &Size);
515 The address we return to the user is one 'long' BELOW the address of
516 the block. This protects our 'size' field, so we can tell the size
517 of the block when he returns it to us with xiFree(). Also, he better not
518 touch the 'size' field at the end of the block either. (That would be
519 nasty of him, as he would be touching memory outside of the bytes he
522 return((char *) (area + 1));
526 :h2 id=addmem.addmemory() - Initialize Free Memory
528 This routine should be called at initialization to initialize the
529 free chain. There is no standard way to do this in C.
530 We want the memory dispensed by malloc to be aligned on a double word
531 boundary (because some machines either require alignment, or are
532 more efficient if accesses are aligned). Since the total size of
533 any block created by malloc is an integral number of double words,
534 all we have to do to ensure alignment is to adjust each large block
535 added to the free chain to start on an odd long-word boundary.
536 (Malloc's size field will occupy the odd long and the user's memory
537 will then begin on an even boundary.) Since we fill in additional
538 size fields at the beginning and end of each of the large freeblocks,
539 we need only adjust the address passed to addmemory to a double word
543 #define MAXAREAS 10 /* there can be this many calls to addmemory() */
545 static long *freearea[MAXAREAS] = { NULL }; /* so we can report later */
547 void addmemory(addr, size)
548 register long *addr; /* beginning of free area */
549 register long size; /* number of bytes of free area */
551 register int i; /* loop index variable */
552 register long *aaddr; /* aligned beginning of free area */
555 printf("malloc has DEBUGWORDS=%d\n", DEBUGWORDS);
558 First link together firstfree and lastfree if necessary:
560 if (firstfree.fore == NULL) {
561 firstfree.fore = &lastfree;
562 lastfree.back = &firstfree;
565 We'll record where the area was that was given to us for later reports:
567 for (i=0; i < MAXAREAS; i++)
568 if (freearea[i] == NULL) break;
570 abort("too many addmemory()s");
571 aaddr = (long *) ( ((long) addr + sizeof(double) - 1) & - (long)sizeof(double) );
572 size -= (char *) aaddr - (char *) addr;
575 Convert 'size' to number of longs, and store '-size' guards at the
576 beginning and end of this area so we will not accidentally recombine the
579 size /= sizeof(long);
581 AvailableWords += size - 2;
583 aaddr[size - 1] = aaddr[0] = -size;
585 Finally, call 'freeuncombinable' to put the remaining memory on the
588 freeuncombinable(aaddr + 1, size - 2);
592 :h3.delmemory() - Delete Memory Pool
599 firstfree.fore = &lastfree;
600 lastfree.back = &firstfree;
601 firstcombined = &lastfree;
603 for (i=0; i<MAXAREAS; i++)
610 :h3.dumpchain() - Print the Chain of Free Blocks
615 register struct freeblock *p; /* current free block */
616 register long size; /* size of block */
617 register struct freeblock *back; /* block before 'p' */
618 register int i; /* temp variable for counting */
620 printf("DUMPING FAST FREE LIST:\n");
622 for (p = firstfree.fore, i=uncombined; p != firstcombined;
625 abort("too many uncombined areas");
627 printf(". . . area @ %08x, size = %ld\n", p, -size);
628 if (size >= 0 || size != ((int *) p)[-1 - size])
629 abort("dumpchain: bad size");
631 abort("dumpchain: bad back");
634 printf("DUMPING COMBINED FREE LIST:\n");
635 for (; p != &lastfree; p = p->fore) {
637 printf(". . . area @ %08x, size = %d\n", p, size);
638 if (size <= 0 || size != ((int *) p)[size - 1])
639 abort("dumpchain: bad size");
641 abort("dumpchain: bad back");
644 if (back != lastfree.back)
645 abort("dumpchain: bad lastfree");
649 :h3.reportarea() - Display a Contiguous Set of Memory Blocks
652 static reportarea(area)
653 register long *area; /* start of blocks (from addmemory) */
655 register long size; /* size of current block */
656 register long wholesize; /* size of original area */
657 register struct freeblock *p; /* pointer to block */
661 wholesize = - *area++;
664 while (wholesize > 0) {
670 printf("Allocated %5d bytes at %08x, first words=%08x %08x\n",
671 size * sizeof(long), area + 1, area[1], area[2]);
673 printf(" ...Last operator: %s\n",
674 (char *)area[size-DEBUGWORDS-1]);
676 for (i = size - DEBUGWORDS; i < size - 2; i += 8) {
679 printf(" %08x", area[i+j]);
685 printf("Free %d bytes at %x\n", size * sizeof(long),
688 abort("zero sized memory block");
690 for (p = firstfree.fore; p != NULL; p = p->fore)
691 if ((long *) p == area) break;
692 if ((long *) p != area)
693 abort("not found on forward chain");
695 for (p = lastfree.back; p != NULL; p = p->back)
696 if ((long *) p == area) break;
697 if ((long *) p != area)
698 abort("not found on backward chain");
700 if (area[0] != area[size - 1])
701 abort("unmatched check sizes");
708 :h3.MemReport() - Display All of Memory
717 for (i=0; i<MAXAREAS; i++)
718 reportarea(freearea[i]);
722 :h3.MemBytesAvail - Display Number of Bytes Now Available
727 printf("There are now %d bytes available\n", AvailableWords *