(gnus-cache-enter-remove-article, gnus-cache-possibly-remove-articles):
[emacs.git] / src / old-ralloc.c
blob28562994e9aa3c55c9ecff82c46d610d919d973b
1 /* Block-relocating memory allocator.
2 Copyright (C) 1990 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20 /* This package works by allocating blocks from a zone of memory
21 above that used by malloc (). When malloc needs more space that
22 would enter our zone, we relocate blocks upward. The bottom of
23 our zone is kept in the variable `virtual_break_value'. The top
24 of our zone is indicated by `real_break_value'.
26 As blocks are freed, a free list is maintained and we attempt
27 to satisfy further requests for space using a first-fit policy.
28 If there are holes, but none fit, memory is compacted and a new
29 block is obtained at the top of the zone.
31 NOTE that our blocks are always rounded to page boundaries. */
34 NOTES:
36 Once this is stable, I can speed things up by intially leaving a large
37 gap between real_break_value and true_break_value, or maybe making
38 a large hole before the first block.
40 If we also kept track of size_wanted, we could gain some
41 extra space upon compactification.
43 Perhaps we should just note a hole when malloc does doing sbrk(-n)?
45 Relocating downward upon freeing the first block would simplify
46 other things.
48 When r_alloc places a block in a hole, we could easily check if there's
49 much more than required, and leave a hole.
52 #include "mem_limits.h"
54 static POINTER r_alloc_sbrk ();
55 static POINTER sbrk ();
56 static POINTER brk ();
58 /* Variable `malloc' uses for the function which gets more space
59 from the system. */
60 extern POINTER (*__morecore) ();
62 /* List of variables which point into the associated data block. */
63 struct other_pointer
65 POINTER *location;
66 struct other_pointer *next;
69 /* List describing all the user's pointers to relocatable blocks. */
70 typedef struct rel_pointers
72 struct rel_pointers *next;
73 struct rel_pointers *prev;
74 struct other_pointer *others; /* Other variables which use this block. */
75 POINTER *location; /* Location of the block's pointer. */
76 POINTER block; /* Address of the actual data. */
77 int size; /* The size of the block. */
78 } relocatable_pointer;
80 #define REL_NIL ((struct rel_pointers *) 0)
82 static relocatable_pointer *pointer_list;
83 static relocatable_pointer *last_pointer;
85 #define MAX_HOLES 2
87 /* Vector of available holes among allocated blocks. This can include
88 a hole at the beginning of the list, but never the end. */
89 typedef struct
91 POINTER address;
92 unsigned int size;
93 } hole_descriptor;
95 static hole_descriptor r_alloc_holes[MAX_HOLES];
97 /* Number of holes currently available. */
98 static int holes;
100 /* The process break value (i.e., curbrk) */
101 static POINTER real_break_value;
103 /* The REAL (i.e., page aligned) break value. */
104 static POINTER true_break_value;
106 /* Address of start of data space in use by relocatable blocks.
107 This is what `malloc' thinks is the process break value. */
108 static POINTER virtual_break_value;
110 /* Nonzero if we have told `malloc' to start using `r_alloc_sbrk'
111 instead of calling `sbrk' directly. */
112 int r_alloc_in_use;
114 #define PAGE (getpagesize ())
115 #define ALIGNED(addr) (((unsigned int) (addr) & (PAGE - 1)) == 0)
116 #define ROUNDUP(size) (((unsigned int) (size) + PAGE) & ~(PAGE - 1))
119 Level number of warnings already issued.
120 0 -- no warnings issued.
121 1 -- 75% warning already issued.
122 2 -- 85% warning already issued.
124 static int warnlevel;
126 /* Function to call to issue a warning;
127 0 means don't issue them. */
128 static void (*warnfunction) ();
130 /* Call this to start things off. It determines the current process
131 break value, as well as the `true' break value--because the system
132 allocates memory in page increments, if the break value is not page
133 aligned it means that space up to the next page boundary is actually
134 available. */
136 void
137 malloc_init (start, warn_func)
138 POINTER start;
139 void (*warn_func) ();
141 r_alloc_in_use = 1;
142 __morecore = r_alloc_sbrk;
144 virtual_break_value = real_break_value = sbrk (0);
145 if (ALIGNED (real_break_value))
146 true_break_value = real_break_value;
147 else
148 true_break_value = (POINTER) ROUNDUP (real_break_value);
150 if (start)
151 data_space_start = start;
152 lim_data = 0;
153 warnlevel = 0;
154 warnfunction = warn_func;
156 get_lim_data ();
159 /* Get more space for us to use. Return a pointer to SIZE more
160 bytes of space. SIZE is internally rounded up to a page boundary,
161 and requests for integral pages prefetch an extra page. */
163 static POINTER
164 get_more_space (size)
165 unsigned int size;
167 unsigned int margin = true_break_value - real_break_value;
168 unsigned int get;
169 POINTER old_break = real_break_value;
171 if (size == 0)
172 return real_break_value;
174 if (size <= margin)
176 real_break_value += size;
177 return old_break;
180 get = ROUNDUP (size - margin);
181 if (sbrk (get) < (POINTER) 0)
182 return NULL;
184 true_break_value += get;
185 real_break_value = (old_break + size);
187 return old_break;
190 /* Relinquish size bytes of space to the system. Space is only returned
191 in page increments. If successful, return real_break_value. */
193 static POINTER
194 return_space (size)
195 unsigned int size;
197 unsigned int margin = (true_break_value - real_break_value) + size;
198 unsigned int to_return = (margin / PAGE) * PAGE;
199 unsigned new_margin = margin % PAGE;
201 true_break_value -= to_return;
202 if (! brk (true_break_value))
203 return NULL;
205 real_break_value = true_break_value - new_margin;
206 return real_break_value;
209 /* Record a new hole in memory beginning at ADDRESS of size SIZE.
210 Holes are ordered by location. Adjacent holes are merged.
211 Holes are zero filled before being noted. */
213 static void
214 note_hole (address, size)
215 POINTER address;
216 int size;
218 register int this_hole = holes - 1; /* Start at the last hole. */
219 register POINTER end = address + size; /* End of the hole. */
220 register int i;
222 if (holes)
224 /* Find the hole which should precede this new one. */
225 while (this_hole >= 0 && r_alloc_holes[this_hole].address > address)
226 this_hole--;
228 /* Can we merge with preceding? */
229 if (this_hole >= 0
230 && r_alloc_holes[this_hole].address + r_alloc_holes[this_hole].size
231 == address)
233 r_alloc_holes[this_hole].size += size;
235 if (this_hole == holes - 1)
236 return;
238 /* Can we also merge with following? */
239 if (end == r_alloc_holes[this_hole + 1].address)
241 r_alloc_holes[this_hole].size
242 += r_alloc_holes[this_hole + 1].size;
244 for (i = this_hole + 1; i < holes - 1; i++)
245 r_alloc_holes[i] = r_alloc_holes[i + 1];
246 holes--;
249 return;
252 if (this_hole < holes - 1) /* there are following holes */
254 register int next_hole = this_hole + 1;
256 /* Can we merge with the next hole? */
257 if (end == r_alloc_holes[next_hole].address)
259 r_alloc_holes[next_hole].address = address;
260 r_alloc_holes[next_hole].size += size;
261 return;
264 /* Can't merge, so insert. */
265 for (i = holes; i > next_hole; i--)
266 r_alloc_holes[i] = r_alloc_holes[i - 1];
267 r_alloc_holes[next_hole].address = address;
268 r_alloc_holes[next_hole].size = size;
269 holes++;
271 return;
273 else /* Simply add this hole at the end. */
275 r_alloc_holes[holes].address = address;
276 r_alloc_holes[holes].size = size;
277 holes++;
279 return;
282 abort ();
284 else /* Make the first hole. */
286 holes = 1;
287 r_alloc_holes[0].address = address;
288 r_alloc_holes[0].size = size;
292 /* Mark hole HOLE as no longer available by re-organizing the vector.
293 HOLE is the Nth hole, beginning with 0. This doesn *not* affect memory
294 organization. */
296 static void
297 delete_hole (hole)
298 int hole;
300 register int i;
302 for (i = hole; i < holes - 1; i++)
303 r_alloc_holes[i] = r_alloc_holes[i + 1];
305 holes--;
308 /* Insert a newly allocated pointer, NEW_PTR, at the appropriate
309 place in our list. */
311 static void
312 insert (new_ptr)
313 register relocatable_pointer *new_ptr;
315 register relocatable_pointer *this_ptr = pointer_list;
317 while (this_ptr != REL_NIL && this_ptr->block < new_ptr->block)
318 this_ptr = this_ptr->next;
320 if (this_ptr == REL_NIL)
321 abort (); /* Use `attach' for appending. */
323 new_ptr->next = this_ptr;
324 new_ptr->prev = this_ptr->prev;
325 this_ptr->prev = new_ptr;
327 if (this_ptr == pointer_list)
328 pointer_list = new_ptr;
329 else
330 new_ptr->prev->next = new_ptr;
333 /* Attach a newly allocated pointer, NEW_PTR, to the end of our list. */
335 static void
336 attach (new_ptr)
337 relocatable_pointer *new_ptr;
339 if (pointer_list == REL_NIL)
341 pointer_list = new_ptr;
342 last_pointer = new_ptr;
343 new_ptr->next = new_ptr->prev = REL_NIL;
345 else
347 new_ptr->next = REL_NIL;
348 last_pointer->next = new_ptr;
349 new_ptr->prev = last_pointer;
350 last_pointer = new_ptr;
354 static relocatable_pointer *
355 find_block (block)
356 POINTER block;
358 register relocatable_pointer *this_ptr = pointer_list;
360 while (this_ptr != REL_NIL && this_ptr->block != block)
361 this_ptr = this_ptr->next;
363 return this_ptr;
366 static relocatable_pointer *
367 find_location (address)
368 POINTER *address;
370 register relocatable_pointer *this_ptr = pointer_list;
372 while (this_ptr != REL_NIL && this_ptr->location != address)
374 struct other_pointer *op = this_ptr->others;
376 while (op != (struct other_pointer *) 0)
378 if (op->location == address)
379 return this_ptr;
381 op = op->next;
384 this_ptr = this_ptr->next;
387 return this_ptr;
391 static void compactify ();
393 /* Record of last new block allocated. */
394 static relocatable_pointer *last_record;
396 /* Allocate a block of size SIZE and record that PTR points to it.
397 If successful, store the address of the block in *PTR and return
398 it as well. Otherwise return NULL. */
400 POINTER
401 r_alloc (ptr, size)
402 POINTER *ptr;
403 int size;
405 register relocatable_pointer *record
406 = (relocatable_pointer *) malloc (sizeof (relocatable_pointer));
407 register POINTER block;
409 /* If we can't get space to record this pointer, fail. */
410 if (record == 0)
411 return NULL;
413 last_record = record;
415 if (holes) /* Search for a hole the right size. */
417 int i;
419 for (i = 0; i < holes; i++)
420 if (r_alloc_holes[i].size >= size)
422 record->location = ptr;
423 record->others = (struct other_pointer *) 0;
424 record->block = *ptr = r_alloc_holes[i].address;
425 if (r_alloc_holes[i].size > ROUNDUP (size))
427 record->size = ROUNDUP (size);
428 r_alloc_holes[i].size -= ROUNDUP (size);
429 r_alloc_holes[i].address += ROUNDUP (size);
431 else
433 record->size = r_alloc_holes[i].size;
434 delete_hole (i);
436 insert (record);
438 *ptr = record->block;
439 return record->block;
442 /* No holes large enough. Burp. */
443 compactify ();
446 /* No holes: grow the process. */
447 block = get_more_space (size);
448 if (block == NULL)
450 free (record);
451 return NULL;
454 /* Return the address of the block. */
455 *ptr = block;
457 /* Record and append this pointer to our list. */
458 record->location = ptr;
459 record->others = (struct other_pointer *) 0;
460 record->block = block;
461 record->size = size;
462 attach (record);
464 return block;
467 /* Declare VAR to be a pointer which points into the block of r_alloc'd
468 memory at BLOCK.
470 If VAR is already delcared for this block, simply return.
471 If VAR currently points to some other block, remove that declaration
472 of it, then install the new one.
474 Return 0 if successful, -1 otherwise. */
477 r_alloc_declare (var, block)
478 POINTER *var;
479 register POINTER block;
481 register relocatable_pointer *block_ptr = find_block (block);
482 relocatable_pointer *var_ptr = find_location (var);
483 register struct other_pointer *other;
485 if (block_ptr == REL_NIL)
486 abort ();
488 if (var_ptr != REL_NIL) /* Var already declared somewhere. */
490 register struct other_pointer *po;
492 if (var_ptr == block_ptr) /* Var already points to this block. */
493 return 0;
495 po = (struct other_pointer *) 0;
496 other = var_ptr->others;
497 while (other && other->location != var)
499 po = other;
500 other = other->next;
503 if (!other) /* This only happens if the location is */
504 abort (); /* the main pointer and not an `other' */
506 if (po) /* In the chain */
508 po->next = other->next;
509 free (other);
511 else /* Only element of the chain */
513 free (var_ptr->others);
514 var_ptr->others = (struct other_pointer *) 0;
518 /* Install this variable as an `other' element */
520 other = (struct other_pointer *) malloc (sizeof (struct other_pointer));
522 if (other == 0)
523 return -1;
525 /* If the malloc relocated this data block, adjust this variable. */
526 if (block != block_ptr->block)
528 int offset = block_ptr->block - block;
530 *var += offset;
533 other->location = var;
534 other->next = (struct other_pointer *) 0;
536 if (block_ptr->others == (struct other_pointer *) 0)
537 block_ptr->others = other;
538 else
540 register struct other_pointer *op = block_ptr->others;
542 while (op->next != (struct other_pointer *) 0)
543 op = op->next;
544 op->next = other;
547 return 0;
550 /* Recursively free the linked list of `other' pointers to a block. */
552 static void
553 free_others (another)
554 struct other_pointer *another;
556 if (another == (struct other_pointer *) 0)
557 return;
559 free_others (another->next);
560 free (another);
563 /* Remove the element pointed to by PTR from the doubly linked list.
564 Record the newly freed space in `holes', unless it was at the end,
565 in which case return that space to the system. Return 0 if successful,
566 -1 otherwise. */
569 r_alloc_free (ptr)
570 register POINTER *ptr;
572 register relocatable_pointer *this_ptr = find_block (*ptr);
574 if (this_ptr == REL_NIL)
575 return -1;
576 else
578 register relocatable_pointer *prev = this_ptr->prev;
579 register relocatable_pointer *next = this_ptr->next;
580 if (next && prev) /* Somewhere in the middle */
582 next->prev = prev;
583 prev->next = next;
585 else if (prev) /* Last block */
587 prev->next = REL_NIL;
588 last_pointer = prev;
589 return_space (this_ptr->size);
590 free_others (this_ptr->others);
591 free (this_ptr);
593 return 0;
595 else if (next) /* First block */
597 next->prev = REL_NIL;
598 pointer_list = next;
600 else if (this_ptr = pointer_list) /* ONLY block */
602 pointer_list = REL_NIL;
603 last_pointer = REL_NIL;
604 if (holes) /* A hole precedes this block. */
606 holes = 0;
607 return_space (real_break_value - virtual_break_value);
609 else
610 return_space (this_ptr->size);
612 if (real_break_value != virtual_break_value)
613 abort ();
615 free_others (this_ptr->others);
616 free (this_ptr);
617 /* Turn off r_alloc_in_use? */
619 return 0;
621 else
622 abort (); /* Weird shit */
624 free_others (this_ptr->others);
625 free (this_ptr);
626 bzero (this_ptr->block, this_ptr->size);
627 note_hole (this_ptr->block, this_ptr->size);
629 if (holes == MAX_HOLES)
630 compactify ();
633 return 0;
636 /* Change the size of the block pointed to by the thing in PTR.
637 If neccessary, r_alloc a new block and copy the data there.
638 Return a pointer to the block if successfull, NULL otherwise.
640 Note that if the size requested is less than the actual bloc size,
641 nothing is done and the pointer is simply returned. */
643 POINTER
644 r_re_alloc (ptr, size)
645 POINTER *ptr;
646 int size;
648 register relocatable_pointer *this_ptr = find_block (*ptr);
649 POINTER block;
651 if (! this_ptr)
652 return NULL;
654 if (this_ptr->size >= size) /* Already have enough space. */
655 return *ptr;
657 /* Here we could try relocating the blocks just above... */
658 block = r_alloc (ptr, size);
659 if (block)
661 bcopy (this_ptr->block, block, this_ptr->size);
662 if (this_ptr->others)
663 last_record->others = this_ptr->others;
665 if (! r_alloc_free (this_ptr->block))
666 abort ();
668 *ptr = block;
669 return block;
672 return NULL;
676 /* Move and relocate all blocks from FIRST_PTR to LAST_PTR, inclusive,
677 downwards to space starting at ADDRESS. */
679 static int
680 move_blocks_downward (first_ptr, last_ptr, address)
681 relocatable_pointer *first_ptr, *last_ptr;
682 POINTER address;
684 int size = (last_ptr->block + last_ptr->size) - first_ptr->block;
685 register relocatable_pointer *this_ptr = first_ptr;
686 register offset = first_ptr->block - address;
687 register struct other_pointer *op;
689 /* Move all the data. */
690 bcopy (first_ptr->block, address, size);
692 /* Now relocate all the pointers to those blocks. */
693 while (1)
695 this_ptr->block -= offset;
696 *this_ptr->location = this_ptr->block;
698 op = this_ptr->others;
699 while (op != (struct other_pointer *) 0)
701 *op->location -= offset;
702 op = op->next;
705 if (this_ptr == last_ptr)
706 return;
707 else
708 this_ptr = this_ptr->next;
711 return size;
714 /* Burp our memory zone. */
716 static void
717 compactify ()
719 register relocatable_pointer *this_ptr = pointer_list;
720 relocatable_pointer *first_to_move;
721 register relocatable_pointer *last_to_move;
722 hole_descriptor *this_hole = &r_alloc_holes[0];
723 register hole_descriptor *next_hole;
724 register POINTER end; /* First address after hole */
725 unsigned int space_regained = 0;
727 while (holes) /* While there are holes */
729 /* Find the first block after this hole. */
730 end = this_hole->address + this_hole->size;
731 while (this_ptr && this_ptr->block != end)
732 this_ptr = this_ptr->next;
734 if (! this_ptr)
735 abort ();
737 next_hole = this_hole + 1;
738 last_to_move = first_to_move = this_ptr;
739 this_ptr = this_ptr->next;
741 /* Note all blocks located before the next hole. */
742 while (this_ptr && this_ptr->block < next_hole->address)
744 last_to_move = this_ptr;
745 this_ptr = this_ptr->next;
747 space_regained +=
748 move_blocks_downward (first_to_move, last_to_move, this_hole->address);
750 holes--;
751 this_hole = next_hole;
754 return_space (space_regained);
757 /* Relocate the list elements from the beginning of the list up to and
758 including UP_TO_THIS_PTR to the area beginning at FREE_SPACE, which is
759 after all current blocks.
761 First copy all the data, then adjust the pointers and reorganize
762 the list. NOTE that this *only* works for contiguous blocks. */
764 static unsigned int
765 relocate_to_end (up_to_this_ptr, free_space)
766 register relocatable_pointer *up_to_this_ptr;
767 POINTER free_space;
769 register relocatable_pointer *this_ptr;
770 POINTER block_start = pointer_list->block;
771 POINTER block_end = up_to_this_ptr->block + up_to_this_ptr->size;
772 unsigned int total_size = block_end - block_start;
773 unsigned int offset = (int) (free_space - block_start);
775 bcopy (block_start, free_space, total_size);
776 for (this_ptr = up_to_this_ptr; this_ptr; this_ptr = this_ptr->prev)
778 struct other_pointer *op = this_ptr->others;
780 *this_ptr->location += offset;
781 this_ptr->block += offset;
783 while (op != (struct other_pointer *) 0)
785 *op->location += offset;
786 op = op->next;
790 /* Connect the head to the tail. */
791 last_pointer->next = pointer_list;
792 pointer_list->prev = last_pointer;
794 /* Disconnect */
795 up_to_this_ptr->next->prev = REL_NIL;
796 pointer_list = up_to_this_ptr->next;
797 up_to_this_ptr->next = REL_NIL;
798 last_pointer = up_to_this_ptr;
800 return total_size; /* of space relocated. */
803 /* Relocate the list elements from FROM_THIS_PTR to (and including)
804 the last to the zone beginning at FREE_SPACE, which is located
805 before any blocks.
807 First copy all the data, then adjust the pointers and reorganize
808 the list. NOTE that this *only* works for contiguous blocks. */
810 static unsigned int
811 relocate_to_beginning (from_this_ptr, free_space)
812 register relocatable_pointer *from_this_ptr;
813 POINTER free_space;
815 POINTER block_start = from_this_ptr->block;
816 POINTER block_end = last_pointer->block + last_pointer->size;
817 unsigned int total_size = (int) (block_end - block_start);
818 unsigned int offset = (int) (from_this_ptr->block - free_space);
819 register relocatable_pointer *this_ptr;
821 bcopy (block_start, free_space, total_size);
822 for (this_ptr = from_this_ptr; this_ptr; this_ptr = this_ptr->next)
824 struct other_pointer *op = this_ptr->others;
826 *this_ptr->location -= offset;
827 this_ptr->block -= offset;
829 while (op != (struct other_pointer *) 0)
831 *op->location -= offset;
832 op = op->next;
836 /* Connect the end to the beginning. */
837 last_pointer->next = pointer_list;
838 pointer_list->prev = last_pointer;
840 /* Disconnect and reset first and last. */
841 from_this_ptr->prev->next = REL_NIL;
842 last_pointer = from_this_ptr->prev;
843 pointer_list = from_this_ptr;
844 pointer_list->prev = REL_NIL;
846 return total_size; /* of space moved. */
849 /* Relocate any blocks neccessary, either upwards or downwards,
850 to obtain a space of SIZE bytes. Assumes we have at least one block. */
852 static unsigned int
853 relocate (size)
854 register int size;
856 register relocatable_pointer *ptr;
857 register int got = 0;
859 if (size > 0) /* Up: Relocate enough blocs to get SIZE. */
861 register POINTER new_space;
863 for (ptr = pointer_list; got < size && ptr; ptr = ptr->next)
864 got += ptr->size;
866 if (ptr == REL_NIL)
867 ptr = last_pointer;
869 new_space = get_more_space (size);
870 if (!new_space)
871 return 0;
873 return (relocate_to_end (ptr, pointer_list->block + size));
876 if (size < 0) /* Down: relocate as many blocs as will
877 fit in SIZE bytes of space. */
879 register POINTER to_zone;
880 unsigned int moved;
882 for (ptr = last_pointer; got >= size && ptr; ptr = ptr->prev)
883 got -= ptr->size;
885 if (ptr == REL_NIL)
886 ptr = pointer_list;
887 else
889 /* Back off one block to be <= size */
890 got += ptr->size;
891 ptr = ptr->next;
894 if (got >= size)
896 to_zone = virtual_break_value - size + got;
897 moved = relocate_to_beginning (ptr, to_zone);
898 if (moved)
899 return_space (moved);
901 return moved;
904 return 0;
907 abort ();
910 /* This function encapsulates `sbrk' to preserve the relocatable blocks.
911 It is called just like `sbrk'. When relocatable blocks are in use,
912 `malloc' must use this function instead of `sbrk'. */
914 POINTER
915 r_alloc_sbrk (size)
916 unsigned int size;
918 POINTER new_zone; /* Start of the zone we will return. */
920 #if 0
921 if (! r_alloc_in_use)
922 return (POINTER) sbrk (size);
923 #endif
925 if (size == 0)
926 return virtual_break_value;
928 if (size > 0) /* Get more space */
930 register unsigned int space;
932 if (pointer_list == REL_NIL)
934 POINTER space = get_more_space (size);
936 virtual_break_value = real_break_value;
937 return space;
940 new_zone = virtual_break_value;
942 /* Check if there is a hole just before the buffer zone. */
943 if (holes && r_alloc_holes[0].address == virtual_break_value)
945 if (r_alloc_holes[0].size > size)
947 /* Adjust the hole size. */
948 r_alloc_holes[0].size -= size;
949 r_alloc_holes[0].address += size;
950 virtual_break_value += size;
952 return new_zone;
955 if (r_alloc_holes[0].size == size)
957 virtual_break_value += size;
958 delete_hole (0);
960 return new_zone;
963 /* Adjust the size requested by space
964 already available in this hole. */
965 size -= r_alloc_holes[0].size;
966 virtual_break_value += r_alloc_holes[0].size;
967 delete_hole (0);
970 space = relocate (size);
971 if (!space)
972 return (POINTER) -1;
974 #ifdef REL_ALLOC_SAVE_SPACE
975 move_blocks_downward
976 #else
977 bzero (new_zone, space);
978 if (space > size)
979 note_hole (new_zone + size, space - size);
980 #endif /* REL_ALLOC_SAVE_SPACE */
982 virtual_break_value += size;
983 return new_zone;
985 else /* Return space to system */
987 int moved;
988 int left_over;
989 POINTER old_break_value;
991 if (pointer_list == REL_NIL)
993 POINTER space = return_space (-size);
994 virtual_break_value = real_break_value;
996 return space;
999 if (holes && r_alloc_holes[0].address == virtual_break_value)
1001 size -= r_alloc_holes[0].size;
1002 delete_hole (0);
1005 moved = relocate (size);
1006 old_break_value = virtual_break_value;
1008 if (!moved)
1009 return (POINTER) -1;
1011 left_over = moved + size;
1012 virtual_break_value += size;
1014 if (left_over)
1016 #ifdef REL_ALLOC_SAVE_SPACE
1017 move_blocks_downward
1018 #else
1019 bzero (virtual_break_value, left_over);
1020 note_hole (virtual_break_value, left_over);
1021 #endif /* not REL_ALLOC_SAVE_SPACE */
1024 return old_break_value;
1028 /* For debugging */
1030 #include <stdio.h>
1032 void
1033 memory_trace ()
1035 relocatable_pointer *ptr;
1036 int i;
1038 fprintf (stderr, "virtual: 0x%x\n real: 0x%x\n true: 0x%x\n\n",
1039 virtual_break_value, real_break_value, true_break_value);
1040 fprintf (stderr, "Blocks:\n");
1041 for (ptr = pointer_list; ptr; ptr = ptr->next)
1043 fprintf (stderr, " address: 0x%x\n", ptr->block);
1044 fprintf (stderr, " size: 0x%x\n", ptr->size);
1045 if (ptr->others)
1047 struct other_pointer *op = ptr->others;
1048 fprintf (stderr, " others:", ptr->size);
1049 while (op)
1051 fprintf (stderr, " 0x%x", op->location);
1052 op = op->next;
1054 fprintf (stderr, "\n");
1058 if (holes)
1060 fprintf (stderr, "\nHoles:\n");
1061 for (i = 0; i < holes; i++)
1063 fprintf (stderr, " address: 0x%x\n", r_alloc_holes[i].address);
1064 fprintf (stderr, " size: 0x%x\n", r_alloc_holes[i].size);
1068 fprintf (stderr, "\n\n");