(SOME_MACHINE_OBJECTS): Add msdos.o and x*.o files.
[bpt/emacs.git] / src / ralloc.c
CommitLineData
dcfdbac7 1/* Block-relocating memory allocator.
c6c5df7f 2 Copyright (C) 1993 Free Software Foundation, Inc.
dcfdbac7
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* NOTES:
21
eb8c3be9 22 Only relocate the blocs necessary for SIZE in r_alloc_sbrk,
dcfdbac7
JB
23 rather than all of them. This means allowing for a possible
24 hole between the first bloc and the end of malloc storage. */
25
2c46d29f 26#ifdef emacs
aef4d570 27
18160b98 28#include <config.h>
956ace37 29#include "lisp.h" /* Needed for VALBITS. */
2c46d29f 30
aef4d570
RM
31#undef NULL
32
f275fd9a
RS
33/* The important properties of this type are that 1) it's a pointer, and
34 2) arithmetic on it should work as if the size of the object pointed
35 to has a size of 1. */
a8c0e5ea 36#if 0 /* Arithmetic on void* is a GCC extension. */
f275fd9a
RS
37#ifdef __STDC__
38typedef void *POINTER;
39#else
1df181b6
RM
40
41#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
44
f275fd9a 45typedef char *POINTER;
1df181b6 46
f275fd9a 47#endif
a8c0e5ea
RS
48#endif /* 0 */
49
50/* Unconditionally use char * for this. */
51typedef char *POINTER;
f275fd9a
RS
52
53typedef unsigned long SIZE;
54
2c46d29f
RS
55/* Declared in dispnew.c, this version doesn't screw up if regions
56 overlap. */
57extern void safe_bcopy ();
2c46d29f 58
aef4d570
RM
59#include "getpagesize.h"
60
61#else /* Not emacs. */
62
2c46d29f 63#include <stddef.h>
aef4d570 64
2c46d29f
RS
65typedef size_t SIZE;
66typedef void *POINTER;
aef4d570 67
aef4d570
RM
68#include <unistd.h>
69#include <malloc.h>
70#include <string.h>
71
2c46d29f 72#define safe_bcopy(x, y, z) memmove (y, x, z)
2c46d29f 73
aef4d570 74#endif /* emacs. */
dcfdbac7
JB
75
76#define NIL ((POINTER) 0)
77
2c46d29f
RS
78/* A flag to indicate whether we have initialized ralloc yet. For
79 Emacs's sake, please do not make this local to malloc_init; on some
80 machines, the dumping procedure makes all static variables
81 read-only. On these machines, the word static is #defined to be
82 the empty string, meaning that r_alloc_initialized becomes an
83 automatic variable, and loses its value each time Emacs is started up. */
84static int r_alloc_initialized = 0;
85
86static void r_alloc_init ();
dcfdbac7 87\f
956ace37
JB
88/* Declarations for working with the malloc, ralloc, and system breaks. */
89
bbc60227
RM
90/* Function to set the real break value. */
91static POINTER (*real_morecore) ();
dcfdbac7
JB
92
93/* The break value, as seen by malloc (). */
94static POINTER virtual_break_value;
95
96/* The break value, viewed by the relocatable blocs. */
97static POINTER break_value;
98
7516b7d5
RS
99/* This is the size of a page. We round memory requests to this boundary. */
100static int page_size;
101
ad3bb3d2
JB
102/* Whenever we get memory from the system, get this many extra bytes. This
103 must be a multiple of page_size. */
7516b7d5
RS
104static int extra_bytes;
105
dcfdbac7
JB
106/* Macros for rounding. Note that rounding to any value is possible
107 by changing the definition of PAGE. */
108#define PAGE (getpagesize ())
f7a009a5
RM
109#define ALIGNED(addr) (((unsigned long int) (addr) & (page_size - 1)) == 0)
110#define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \
111 & ~(page_size - 1))
7516b7d5 112#define ROUND_TO_PAGE(addr) (addr & (~(page_size - 1)))
e429caa2
KH
113
114#define MEM_ALIGN sizeof(double)
115#define MEM_ROUNDUP(addr) (((unsigned long int)(addr) + MEM_ALIGN - 1) \
116 & ~(MEM_ALIGN - 1))
117\f
118/* Data structures of heaps and blocs */
119typedef struct heap
120{
121 struct heap *next;
122 struct heap *prev;
123 POINTER start;
124 POINTER end;
125 POINTER bloc_start; /* start of relocatable blocs */
126} *heap_ptr;
127
128#define NIL_HEAP ((heap_ptr) 0)
129#define HEAP_PTR_SIZE (sizeof (struct heap))
130
131/* Head and tail of the list of heaps. */
132static heap_ptr first_heap, last_heap;
133
134/* These structures are allocated in the malloc arena.
135 The linked list is kept in order of increasing '.data' members.
136 The data blocks abut each other; if b->next is non-nil, then
137 b->data + b->size == b->next->data. */
138typedef struct bp
139{
140 struct bp *next;
141 struct bp *prev;
142 POINTER *variable;
143 POINTER data;
144 SIZE size;
145 POINTER new_data; /* tmporarily used for relocation */
146} *bloc_ptr;
147
148#define NIL_BLOC ((bloc_ptr) 0)
149#define BLOC_PTR_SIZE (sizeof (struct bp))
150
151/* Head and tail of the list of relocatable blocs. */
152static bloc_ptr first_bloc, last_bloc;
153
dcfdbac7 154\f
956ace37
JB
155/* Functions to get and return memory from the system. */
156
e429caa2
KH
157/* Obtain SIZE bytes of space starting at ADDRESS in a heap.
158 If enough space is not presently available in our reserve, this means
159 getting more page-aligned space from the system. If the retuned space
160 is not contiguos to the last heap, allocate a new heap, and append it
161 to the heap list.
dcfdbac7 162
e429caa2
KH
163 Return the address of the space if all went well, or zero if we couldn't
164 allocate the memory. */
165static POINTER
166obtain (address, size)
167 POINTER address;
168 SIZE size;
dcfdbac7 169{
e429caa2
KH
170 heap_ptr heap;
171 SIZE already_available;
dcfdbac7 172
e429caa2 173 for (heap = last_heap; heap; heap = heap->prev)
dcfdbac7 174 {
e429caa2
KH
175 if (heap->start <= address && address <= heap->end)
176 break;
177 }
dcfdbac7 178
e429caa2
KH
179 if (! heap)
180 abort();
dcfdbac7 181
e429caa2
KH
182 while (heap && address + size > heap->end)
183 {
184 heap = heap->next;
185 if (heap == NIL_HEAP)
186 break;
187 address = heap->bloc_start;
dcfdbac7
JB
188 }
189
e429caa2
KH
190 if (heap == NIL_HEAP)
191 {
192 POINTER new = (*real_morecore)(0);
193 SIZE get;
98b7fe02 194
e429caa2 195 already_available = (char *)last_heap->end - (char *)address;
dcfdbac7 196
e429caa2
KH
197 if (new != last_heap->end)
198 {
199 /* Someone else called sbrk(). */
200 heap_ptr new_heap = (heap_ptr) MEM_ROUNDUP(new);
201 POINTER bloc_start = (POINTER) MEM_ROUNDUP((POINTER)(new_heap + 1));
202
203 if ((*real_morecore) (bloc_start - new) != new)
204 return 0;
205
206 new_heap->start = new;
207 new_heap->end = bloc_start;
208 new_heap->bloc_start = bloc_start;
209 new_heap->next = NIL_HEAP;
210 new_heap->prev = last_heap;
211 last_heap->next = new_heap;
212 last_heap = new_heap;
213
214 address = bloc_start;
215 already_available = 0;
216 }
dcfdbac7 217
e429caa2
KH
218 /* Get some extra, so we can come here less often. */
219 get = size + extra_bytes - already_available;
220 get = (char *) ROUNDUP((char *)last_heap->end + get)
221 - (char *) last_heap->end;
dcfdbac7 222
e429caa2
KH
223 if ((*real_morecore) (get) != last_heap->end)
224 return 0;
225
226 last_heap->end += get;
227 }
228
229 return address;
230}
dcfdbac7 231
e429caa2 232/* If the last heap has a excessive space, return it to the system. */
dcfdbac7 233static void
e429caa2 234relinquish ()
dcfdbac7 235{
e429caa2
KH
236 register heap_ptr h;
237 int excess = 0;
238
239 for (h = last_heap; h && break_value < h->end; h = h->prev)
240 {
241 excess += (char *) h->end - (char *) ((break_value < h->bloc_start)
242 ? h->bloc_start : break_value);
243 }
244
245 if (excess > extra_bytes * 2 && (*real_morecore) (0) == last_heap->end)
dcfdbac7 246 {
7516b7d5
RS
247 /* Keep extra_bytes worth of empty space.
248 And don't free anything unless we can free at least extra_bytes. */
e429caa2 249 excess -= extra_bytes;
dcfdbac7 250
e429caa2
KH
251 if ((char *)last_heap->end - (char *)last_heap->bloc_start <= excess)
252 {
253 /* Return the last heap with its header to the system */
254 excess = (char *)last_heap->end - (char *)last_heap->start;
255 last_heap = last_heap->prev;
256 last_heap->next = NIL_HEAP;
257 }
258 else
259 {
260 excess = (char *) last_heap->end
261 - (char *) ROUNDUP((char *)last_heap->end - excess);
262 last_heap->end -= excess;
263 }
dcfdbac7 264
e429caa2
KH
265 if ((*real_morecore) (- excess) == 0)
266 abort ();
267 }
dcfdbac7
JB
268}
269\f
956ace37
JB
270/* The meat - allocating, freeing, and relocating blocs. */
271
956ace37 272/* Find the bloc referenced by the address in PTR. Returns a pointer
dcfdbac7
JB
273 to that block. */
274
275static bloc_ptr
276find_bloc (ptr)
277 POINTER *ptr;
278{
279 register bloc_ptr p = first_bloc;
280
281 while (p != NIL_BLOC)
282 {
283 if (p->variable == ptr && p->data == *ptr)
284 return p;
285
286 p = p->next;
287 }
288
289 return p;
290}
291
292/* Allocate a bloc of SIZE bytes and append it to the chain of blocs.
98b7fe02
JB
293 Returns a pointer to the new bloc, or zero if we couldn't allocate
294 memory for the new block. */
dcfdbac7
JB
295
296static bloc_ptr
297get_bloc (size)
298 SIZE size;
299{
98b7fe02
JB
300 register bloc_ptr new_bloc;
301
302 if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE))
e429caa2 303 || ! (new_bloc->data = obtain (break_value, size)))
98b7fe02
JB
304 {
305 if (new_bloc)
306 free (new_bloc);
307
308 return 0;
309 }
dcfdbac7 310
e429caa2
KH
311 break_value = new_bloc->data + size;
312
dcfdbac7
JB
313 new_bloc->size = size;
314 new_bloc->next = NIL_BLOC;
8c7f1e35 315 new_bloc->variable = (POINTER *) NIL;
e429caa2 316 new_bloc->new_data = 0;
dcfdbac7
JB
317
318 if (first_bloc)
319 {
320 new_bloc->prev = last_bloc;
321 last_bloc->next = new_bloc;
322 last_bloc = new_bloc;
323 }
324 else
325 {
326 first_bloc = last_bloc = new_bloc;
327 new_bloc->prev = NIL_BLOC;
328 }
329
330 return new_bloc;
331}
332
e429caa2
KH
333/* Calculate new locations of blocs in the list begining with BLOC,
334 whose spaces is started at ADDRESS in HEAP. If enough space is
335 not presently available in our reserve, obtain() is called for
336 more space.
337
338 Do not touch the contents of blocs or break_value. */
dcfdbac7 339
e429caa2
KH
340static int
341relocate_blocs (bloc, heap, address)
342 bloc_ptr bloc;
343 heap_ptr heap;
344 POINTER address;
345{
346 register bloc_ptr b = bloc;
ad3bb3d2 347
e429caa2
KH
348 while (b)
349 {
350 while (heap && address + b->size > heap->end)
351 {
352 heap = heap->next;
353 if (heap == NIL_HEAP)
354 break;
355 address = heap->bloc_start;
356 }
dcfdbac7 357
e429caa2
KH
358 if (heap == NIL_HEAP)
359 {
360 register bloc_ptr tb = b;
361 register SIZE s = 0;
362
363 while (tb != NIL_BLOC)
364 {
365 s += tb->size;
366 tb = tb->next;
367 }
368
369 if (! (address = obtain(address, s)))
370 return 0;
371
372 heap = last_heap;
373 }
374
375 b->new_data = address;
376 address += b->size;
377 b = b->next;
378 }
379
380 return 1;
381}
382
383/* Resize BLOC to SIZE bytes. */
384static int
385resize_bloc (bloc, size)
386 bloc_ptr bloc;
387 SIZE size;
dcfdbac7 388{
e429caa2
KH
389 register bloc_ptr b;
390 heap_ptr heap;
391 POINTER address;
392 SIZE old_size;
393
394 if (bloc == NIL_BLOC || size == bloc->size)
395 return 1;
396
397 for (heap = first_heap; heap != NIL_HEAP; heap = heap->next)
398 {
399 if (heap->bloc_start <= bloc->data && bloc->data <= heap->end)
400 break;
401 }
402
403 if (heap == NIL_HEAP)
404 abort();
405
406 old_size = bloc->size;
407 bloc->size = size;
408
409 /* Note that bloc could be moved into the previous heap. */
410 address = bloc->prev ? bloc->prev->data + bloc->prev->size
411 : first_heap->bloc_start;
412 while (heap)
413 {
414 if (heap->bloc_start <= address && address <= heap->end)
415 break;
416 heap = heap->prev;
417 }
418
419 if (! relocate_blocs (bloc, heap, address))
420 {
421 bloc->size = old_size;
422 return 0;
423 }
424
425 if (size > old_size)
426 {
427 for (b = last_bloc; b != bloc; b = b->prev)
428 {
429 safe_bcopy (b->data, b->new_data, b->size);
430 *b->variable = b->data = b->new_data;
431 }
432 safe_bcopy (bloc->data, bloc->new_data, old_size);
433 bzero (bloc->new_data + old_size, size - old_size);
434 *bloc->variable = bloc->data = bloc->new_data;
435 }
436 else
dcfdbac7 437 {
ad3bb3d2
JB
438 for (b = bloc; b != NIL_BLOC; b = b->next)
439 {
e429caa2
KH
440 safe_bcopy (b->data, b->new_data, b->size);
441 *b->variable = b->data = b->new_data;
ad3bb3d2 442 }
ad3bb3d2 443 }
dcfdbac7 444
e429caa2
KH
445 break_value = last_bloc ? last_bloc->data + last_bloc->size
446 : first_heap->bloc_start;
447 return 1;
448}
ad3bb3d2 449
dcfdbac7
JB
450/* Free BLOC from the chain of blocs, relocating any blocs above it
451 and returning BLOC->size bytes to the free area. */
452
453static void
454free_bloc (bloc)
455 bloc_ptr bloc;
456{
e429caa2
KH
457 resize_bloc (bloc, 0);
458
dcfdbac7
JB
459 if (bloc == first_bloc && bloc == last_bloc)
460 {
461 first_bloc = last_bloc = NIL_BLOC;
462 }
463 else if (bloc == last_bloc)
464 {
465 last_bloc = bloc->prev;
466 last_bloc->next = NIL_BLOC;
467 }
468 else if (bloc == first_bloc)
469 {
470 first_bloc = bloc->next;
471 first_bloc->prev = NIL_BLOC;
dcfdbac7
JB
472 }
473 else
474 {
475 bloc->next->prev = bloc->prev;
476 bloc->prev->next = bloc->next;
dcfdbac7
JB
477 }
478
e429caa2 479 relinquish ();
dcfdbac7
JB
480 free (bloc);
481}
482\f
956ace37
JB
483/* Interface routines. */
484
dcfdbac7 485static int use_relocatable_buffers;
81bd58e8 486static int r_alloc_freeze_level;
dcfdbac7 487
98b7fe02 488/* Obtain SIZE bytes of storage from the free pool, or the system, as
2c46d29f 489 necessary. If relocatable blocs are in use, this means relocating
98b7fe02
JB
490 them. This function gets plugged into the GNU malloc's __morecore
491 hook.
492
7516b7d5
RS
493 We provide hysteresis, never relocating by less than extra_bytes.
494
98b7fe02
JB
495 If we're out of memory, we should return zero, to imitate the other
496 __morecore hook values - in particular, __default_morecore in the
497 GNU malloc package. */
dcfdbac7
JB
498
499POINTER
500r_alloc_sbrk (size)
501 long size;
502{
e429caa2
KH
503 register bloc_ptr b;
504 POINTER address;
dcfdbac7
JB
505
506 if (! use_relocatable_buffers)
bbc60227 507 return (*real_morecore) (size);
dcfdbac7 508
e429caa2
KH
509 if (size == 0)
510 return virtual_break_value;
7516b7d5 511
e429caa2 512 if (size > 0)
dcfdbac7 513 {
e429caa2
KH
514 /* Allocate a page-aligned space. GNU malloc would reclaim an
515 extra space if we passed an unaligned one. But we could
516 not always find a space which is contiguos to the previous. */
517 POINTER new_bloc_start;
518 heap_ptr h = first_heap;
519 SIZE get = ROUNDUP(size);
7516b7d5 520
e429caa2
KH
521 address = (POINTER) ROUNDUP(virtual_break_value);
522
523 /* Search the list upward for a heap which is large enough. */
524 while ((char *) h->end < (char *) MEM_ROUNDUP((char *)address + get))
525 {
526 h = h->next;
527 if (h == NIL_HEAP)
528 break;
529 address = (POINTER) ROUNDUP(h->start);
530 }
531
532 /* If not found, obatin more space. */
533 if (h == NIL_HEAP)
534 {
535 get += extra_bytes + page_size;
536
537 if (r_alloc_freeze_level > 0 || ! obtain(address, get))
538 return 0;
98b7fe02 539
e429caa2
KH
540 if (first_heap == last_heap)
541 address = (POINTER) ROUNDUP(virtual_break_value);
542 else
543 address = (POINTER) ROUNDUP(last_heap->start);
544 h = last_heap;
545 }
546
547 new_bloc_start = (POINTER) MEM_ROUNDUP((char *)address + get);
548
549 if (first_heap->bloc_start < new_bloc_start)
550 {
551 /* Move all blocs upward. */
552 if (r_alloc_freeze_level > 0
553 || ! relocate_blocs (first_bloc, h, new_bloc_start))
554 return 0;
555
556 /* Note that (POINTER)(h+1) <= new_bloc_start since
557 get >= page_size, so the following does not destroy the heap
558 header. */
559 for (b = last_bloc; b != NIL_BLOC; b = b->prev)
560 {
561 safe_bcopy (b->data, b->new_data, b->size);
562 *b->variable = b->data = b->new_data;
563 }
564
565 h->bloc_start = new_bloc_start;
566 }
956ace37 567
e429caa2
KH
568 if (h != first_heap)
569 {
570 /* Give up managing heaps below the one the new
571 virtual_break_value points to. */
572 first_heap->prev = NIL_HEAP;
573 first_heap->next = h->next;
574 first_heap->start = h->start;
575 first_heap->end = h->end;
576 first_heap->bloc_start = h->bloc_start;
577
578 if (first_heap->next)
579 first_heap->next->prev = first_heap;
580 else
581 last_heap = first_heap;
582 }
583
584 bzero (address, size);
dcfdbac7 585 }
e429caa2 586 else /* size < 0 */
dcfdbac7 587 {
e429caa2
KH
588 SIZE excess = (char *)first_heap->bloc_start
589 - ((char *)virtual_break_value + size);
590
591 address = virtual_break_value;
592
593 if (r_alloc_freeze_level == 0 && excess > 2 * extra_bytes)
594 {
595 excess -= extra_bytes;
596 first_heap->bloc_start
597 = (POINTER) MEM_ROUNDUP((char *)first_heap->bloc_start - excess);
598
599 relocate_blocs(first_bloc, first_heap, first_heap->bloc_start);
7516b7d5 600
e429caa2
KH
601 for (b = first_bloc; b != NIL_BLOC; b = b->next)
602 {
603 safe_bcopy (b->data, b->new_data, b->size);
604 *b->variable = b->data = b->new_data;
605 }
606 }
607
608 if ((char *)virtual_break_value + size < (char *)first_heap->start)
609 {
610 /* We found an additional space below the first heap */
611 first_heap->start = (POINTER) ((char *)virtual_break_value + size);
612 }
dcfdbac7
JB
613 }
614
e429caa2
KH
615 virtual_break_value = (POINTER) ((char *)address + size);
616 break_value = last_bloc ? last_bloc->data + last_bloc->size
617 : first_heap->bloc_start;
618 if (size < 0)
619 relinquish();
7516b7d5 620
e429caa2 621 return address;
dcfdbac7
JB
622}
623
624/* Allocate a relocatable bloc of storage of size SIZE. A pointer to
625 the data is returned in *PTR. PTR is thus the address of some variable
98b7fe02
JB
626 which will use the data area.
627
628 If we can't allocate the necessary memory, set *PTR to zero, and
629 return zero. */
dcfdbac7
JB
630
631POINTER
632r_alloc (ptr, size)
633 POINTER *ptr;
634 SIZE size;
635{
636 register bloc_ptr new_bloc;
637
2c46d29f
RS
638 if (! r_alloc_initialized)
639 r_alloc_init ();
640
e429caa2 641 new_bloc = get_bloc (MEM_ROUNDUP(size));
98b7fe02
JB
642 if (new_bloc)
643 {
644 new_bloc->variable = ptr;
645 *ptr = new_bloc->data;
646 }
647 else
648 *ptr = 0;
dcfdbac7
JB
649
650 return *ptr;
651}
652
2c46d29f
RS
653/* Free a bloc of relocatable storage whose data is pointed to by PTR.
654 Store 0 in *PTR to show there's no block allocated. */
dcfdbac7
JB
655
656void
657r_alloc_free (ptr)
658 register POINTER *ptr;
659{
660 register bloc_ptr dead_bloc;
661
dcfdbac7
JB
662 dead_bloc = find_bloc (ptr);
663 if (dead_bloc == NIL_BLOC)
664 abort ();
665
666 free_bloc (dead_bloc);
2c46d29f 667 *ptr = 0;
dcfdbac7
JB
668}
669
16a5c729 670/* Given a pointer at address PTR to relocatable data, resize it to SIZE.
98b7fe02
JB
671 Do this by shifting all blocks above this one up in memory, unless
672 SIZE is less than or equal to the current bloc size, in which case
673 do nothing.
dcfdbac7 674
98b7fe02
JB
675 Change *PTR to reflect the new bloc, and return this value.
676
677 If more memory cannot be allocated, then leave *PTR unchanged, and
678 return zero. */
dcfdbac7
JB
679
680POINTER
681r_re_alloc (ptr, size)
682 POINTER *ptr;
683 SIZE size;
684{
16a5c729 685 register bloc_ptr bloc;
dcfdbac7 686
16a5c729
JB
687 bloc = find_bloc (ptr);
688 if (bloc == NIL_BLOC)
dcfdbac7
JB
689 abort ();
690
16a5c729 691 if (size <= bloc->size)
956ace37 692 /* Wouldn't it be useful to actually resize the bloc here? */
dcfdbac7
JB
693 return *ptr;
694
e429caa2 695 if (! resize_bloc (bloc, MEM_ROUNDUP(size)))
98b7fe02
JB
696 return 0;
697
dcfdbac7
JB
698 return *ptr;
699}
81bd58e8
KH
700
701/* Disable relocations, after making room for at least SIZE bytes
702 of non-relocatable heap if possible. The relocatable blocs are
703 guaranteed to hold still until thawed, even if this means that
704 malloc must return a null pointer. */
705void
706r_alloc_freeze (size)
707 long size;
708{
709 /* If already frozen, we can't make any more room, so don't try. */
710 if (r_alloc_freeze_level > 0)
711 size = 0;
712 /* If we can't get the amount requested, half is better than nothing. */
713 while (size > 0 && r_alloc_sbrk (size) == 0)
714 size /= 2;
715 ++r_alloc_freeze_level;
716 if (size > 0)
717 r_alloc_sbrk (-size);
718}
719
720void
721r_alloc_thaw ()
722{
723 if (--r_alloc_freeze_level < 0)
724 abort ();
725}
dcfdbac7
JB
726\f
727/* The hook `malloc' uses for the function which gets more space
728 from the system. */
729extern POINTER (*__morecore) ();
730
eb8c3be9 731/* Initialize various things for memory allocation. */
dcfdbac7 732
2c46d29f
RS
733static void
734r_alloc_init ()
dcfdbac7 735{
e429caa2
KH
736 static struct heap heap_base;
737 POINTER end;
738
2c46d29f 739 if (r_alloc_initialized)
dcfdbac7
JB
740 return;
741
2c46d29f 742 r_alloc_initialized = 1;
bbc60227 743 real_morecore = __morecore;
dcfdbac7 744 __morecore = r_alloc_sbrk;
8c7f1e35 745
e429caa2
KH
746 first_heap = last_heap = &heap_base;
747 first_heap->next = first_heap->prev = NIL_HEAP;
748 first_heap->start = first_heap->bloc_start
749 = virtual_break_value = break_value = (*real_morecore) (0);
aef4d570 750 if (break_value == NIL)
2c46d29f 751 abort ();
8c7f1e35 752
7516b7d5
RS
753 page_size = PAGE;
754 extra_bytes = ROUNDUP (50000);
755
e429caa2 756 first_heap->end = (POINTER) ROUNDUP (first_heap->start);
0e93a7cf
RS
757
758 /* The extra call to real_morecore guarantees that the end of the
759 address space is a multiple of page_size, even if page_size is
760 not really the page size of the system running the binary in
761 which page_size is stored. This allows a binary to be built on a
762 system with one page size and run on a system with a smaller page
763 size. */
e429caa2 764 (*real_morecore) (first_heap->end - first_heap->start);
0e93a7cf 765
2c46d29f
RS
766 /* Clear the rest of the last page; this memory is in our address space
767 even though it is after the sbrk value. */
0e93a7cf
RS
768 /* Doubly true, with the additional call that explicitly adds the
769 rest of that page to the address space. */
e429caa2
KH
770 bzero (first_heap->start, first_heap->end - first_heap->start);
771 virtual_break_value = break_value = first_heap->bloc_start = first_heap->end;
dcfdbac7 772 use_relocatable_buffers = 1;
2c46d29f 773}
e429caa2
KH
774#ifdef DEBUG
775#include <assert.h>
776
777int
778r_alloc_check ()
779{
780 int found = 0;
781 heap_ptr h, ph = 0;
782 bloc_ptr b, pb = 0;
783
784 if (!r_alloc_initialized)
785 return;
786
787 assert(first_heap);
788 assert(last_heap->end <= (POINTER) sbrk(0));
789 assert((POINTER) first_heap < first_heap->start);
790 assert(first_heap->start <= virtual_break_value);
791 assert(virtual_break_value <= first_heap->end);
792
793 for (h = first_heap; h; h = h->next)
794 {
795 assert(h->prev == ph);
796 assert((POINTER) ROUNDUP(h->end) == h->end);
797 assert((POINTER) MEM_ROUNDUP(h->start) == h->start);
798 assert((POINTER) MEM_ROUNDUP(h->bloc_start) == h->bloc_start);
799 assert(h->start <= h->bloc_start && h->bloc_start <= h->end);
800
801 if (ph)
802 {
803 assert (ph->end < h->start);
804 assert (h->start <= (POINTER)h && (POINTER)(h+1) <= h->bloc_start);
805 }
806
807 if (h->bloc_start <= break_value && break_value <= h->end)
808 found = 1;
809
810 ph = h;
811 }
812
813 assert(found);
814 assert(last_heap == ph);
815
816 for (b = first_bloc; b; b = b->next)
817 {
818 assert(b->prev == pb);
819 assert((POINTER) MEM_ROUNDUP(b->data) == b->data);
820 assert((SIZE) MEM_ROUNDUP(b->size) == b->size);
821
822 ph = 0;
823 for (h = first_heap; h; h = h->next)
824 {
825 if (h->bloc_start <= b->data && b->data + b->size <= h->end)
826 break;
827 ph = h;
828 }
829
830 assert(h);
831
832 if (pb && pb->data + pb->size != b->data)
833 {
834 assert(ph && b->data == h->bloc_start);
835 while (ph)
836 {
837 if (ph->bloc_start <= pb->data
838 && pb->data + pb->size <= ph->end)
839 {
840 assert(pb->data + pb->size + b->size > ph->end);
841 break;
842 }
843 else
844 {
845 assert(ph->bloc_start + b->size > ph->end);
846 }
847 ph = ph->prev;
848 }
849 }
850 pb = b;
851 }
852
853 assert(last_bloc == pb);
854
855 if (last_bloc)
856 assert(last_bloc->data + last_bloc->size == break_value);
857 else
858 assert(first_heap->bloc_start == break_value);
859}
860#endif /* DEBUG */