* bookmark.el (bookmark-jump-noselect): Add obsolescence declaration
[bpt/emacs.git] / src / ralloc.c
CommitLineData
177c0ea7 1/* Block-relocating memory allocator.
429ab54e 2 Copyright (C) 1993, 1995, 2000, 2001, 2002, 2003, 2004,
8cabe764 3 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
dcfdbac7
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
dcfdbac7 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
dcfdbac7
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
dcfdbac7
JB
19
20/* NOTES:
21
eb8c3be9 22 Only relocate the blocs necessary for SIZE in r_alloc_sbrk,
dcfdbac7 23 rather than all of them. This means allowing for a possible
abe9ff32 24 hole between the first bloc and the end of malloc storage. */
dcfdbac7 25
2c46d29f 26#ifdef emacs
aef4d570 27
18160b98 28#include <config.h>
956ace37 29#include "lisp.h" /* Needed for VALBITS. */
a4766fd5 30#include "blockinput.h"
0a58f946 31
642a1733
DL
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif
a8c0e5ea 35
0a58f946
GM
36typedef POINTER_TYPE *POINTER;
37typedef size_t SIZE;
f275fd9a 38
2c46d29f
RS
39/* Declared in dispnew.c, this version doesn't screw up if regions
40 overlap. */
0a58f946 41
2c46d29f 42extern void safe_bcopy ();
2c46d29f 43
b0119c68 44#ifdef DOUG_LEA_MALLOC
177c0ea7 45#define M_TOP_PAD -2
b0119c68 46extern int mallopt ();
0a58f946 47#else /* not DOUG_LEA_MALLOC */
a2c23c92 48#ifndef SYSTEM_MALLOC
b1685c5f 49extern size_t __malloc_extra_blocks;
a2c23c92 50#endif /* SYSTEM_MALLOC */
0a58f946 51#endif /* not DOUG_LEA_MALLOC */
49081834 52
d5179acc 53#else /* not emacs */
aef4d570 54
2c46d29f 55#include <stddef.h>
aef4d570 56
2c46d29f
RS
57typedef size_t SIZE;
58typedef void *POINTER;
aef4d570 59
aef4d570
RM
60#include <unistd.h>
61#include <malloc.h>
aef4d570 62
2c46d29f 63#define safe_bcopy(x, y, z) memmove (y, x, z)
d5179acc
RS
64#define bzero(x, len) memset (x, 0, len)
65
66#endif /* not emacs */
2c46d29f 67
0a58f946 68
d5179acc 69#include "getpagesize.h"
dcfdbac7
JB
70
71#define NIL ((POINTER) 0)
72
2c46d29f
RS
73/* A flag to indicate whether we have initialized ralloc yet. For
74 Emacs's sake, please do not make this local to malloc_init; on some
75 machines, the dumping procedure makes all static variables
76 read-only. On these machines, the word static is #defined to be
77 the empty string, meaning that r_alloc_initialized becomes an
0a58f946
GM
78 automatic variable, and loses its value each time Emacs is started
79 up. */
80
2c46d29f
RS
81static int r_alloc_initialized = 0;
82
83static void r_alloc_init ();
0a58f946 84
dcfdbac7 85\f
956ace37
JB
86/* Declarations for working with the malloc, ralloc, and system breaks. */
87
abe9ff32 88/* Function to set the real break value. */
321ed47b 89POINTER (*real_morecore) ();
dcfdbac7 90
abe9ff32 91/* The break value, as seen by malloc. */
dcfdbac7
JB
92static POINTER virtual_break_value;
93
abe9ff32
RS
94/* The address of the end of the last data in use by ralloc,
95 including relocatable blocs as well as malloc data. */
dcfdbac7
JB
96static POINTER break_value;
97
7516b7d5
RS
98/* This is the size of a page. We round memory requests to this boundary. */
99static int page_size;
100
177c0ea7 101/* Whenever we get memory from the system, get this many extra bytes. This
ad3bb3d2 102 must be a multiple of page_size. */
7516b7d5
RS
103static int extra_bytes;
104
dcfdbac7 105/* Macros for rounding. Note that rounding to any value is possible
abe9ff32 106 by changing the definition of PAGE. */
dcfdbac7 107#define PAGE (getpagesize ())
f7a009a5
RM
108#define ALIGNED(addr) (((unsigned long int) (addr) & (page_size - 1)) == 0)
109#define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \
110 & ~(page_size - 1))
7516b7d5 111#define ROUND_TO_PAGE(addr) (addr & (~(page_size - 1)))
e429caa2
KH
112
113#define MEM_ALIGN sizeof(double)
114#define MEM_ROUNDUP(addr) (((unsigned long int)(addr) + MEM_ALIGN - 1) \
115 & ~(MEM_ALIGN - 1))
0a58f946 116
aeac019e
GM
117/* The hook `malloc' uses for the function which gets more space
118 from the system. */
119
120#ifndef SYSTEM_MALLOC
121extern POINTER (*__morecore) ();
122#endif
123
124
e429caa2 125\f
0a58f946
GM
126/***********************************************************************
127 Implementation using sbrk
128 ***********************************************************************/
129
abe9ff32
RS
130/* Data structures of heaps and blocs. */
131
132/* The relocatable objects, or blocs, and the malloc data
133 both reside within one or more heaps.
134 Each heap contains malloc data, running from `start' to `bloc_start',
135 and relocatable objects, running from `bloc_start' to `free'.
136
137 Relocatable objects may relocate within the same heap
138 or may move into another heap; the heaps themselves may grow
139 but they never move.
140
141 We try to make just one heap and make it larger as necessary.
8e6208c5 142 But sometimes we can't do that, because we can't get contiguous
abe9ff32 143 space to add onto the heap. When that happens, we start a new heap. */
177c0ea7 144
e429caa2
KH
145typedef struct heap
146{
147 struct heap *next;
148 struct heap *prev;
abe9ff32 149 /* Start of memory range of this heap. */
e429caa2 150 POINTER start;
abe9ff32 151 /* End of memory range of this heap. */
e429caa2 152 POINTER end;
abe9ff32
RS
153 /* Start of relocatable data in this heap. */
154 POINTER bloc_start;
155 /* Start of unused space in this heap. */
156 POINTER free;
47f13333
RS
157 /* First bloc in this heap. */
158 struct bp *first_bloc;
159 /* Last bloc in this heap. */
160 struct bp *last_bloc;
e429caa2
KH
161} *heap_ptr;
162
163#define NIL_HEAP ((heap_ptr) 0)
164#define HEAP_PTR_SIZE (sizeof (struct heap))
165
abe9ff32
RS
166/* This is the first heap object.
167 If we need additional heap objects, each one resides at the beginning of
168 the space it covers. */
169static struct heap heap_base;
170
171/* Head and tail of the list of heaps. */
e429caa2
KH
172static heap_ptr first_heap, last_heap;
173
174/* These structures are allocated in the malloc arena.
175 The linked list is kept in order of increasing '.data' members.
176 The data blocks abut each other; if b->next is non-nil, then
177c0ea7 177 b->data + b->size == b->next->data.
49f82b3d
RS
178
179 An element with variable==NIL denotes a freed block, which has not yet
180 been collected. They may only appear while r_alloc_freeze > 0, and will be
181 freed when the arena is thawed. Currently, these blocs are not reusable,
8e6208c5 182 while the arena is frozen. Very inefficient. */
49f82b3d 183
e429caa2
KH
184typedef struct bp
185{
186 struct bp *next;
187 struct bp *prev;
188 POINTER *variable;
189 POINTER data;
190 SIZE size;
8e6208c5 191 POINTER new_data; /* temporarily used for relocation */
49f82b3d 192 struct heap *heap; /* Heap this bloc is in. */
e429caa2
KH
193} *bloc_ptr;
194
195#define NIL_BLOC ((bloc_ptr) 0)
196#define BLOC_PTR_SIZE (sizeof (struct bp))
197
abe9ff32 198/* Head and tail of the list of relocatable blocs. */
e429caa2
KH
199static bloc_ptr first_bloc, last_bloc;
200
49f82b3d
RS
201static int use_relocatable_buffers;
202
203/* If >0, no relocation whatsoever takes place. */
204static int r_alloc_freeze_level;
205
dcfdbac7 206\f
956ace37
JB
207/* Functions to get and return memory from the system. */
208
abe9ff32
RS
209/* Find the heap that ADDRESS falls within. */
210
211static heap_ptr
212find_heap (address)
213 POINTER address;
214{
215 heap_ptr heap;
216
217 for (heap = last_heap; heap; heap = heap->prev)
218 {
219 if (heap->start <= address && address <= heap->end)
220 return heap;
221 }
222
223 return NIL_HEAP;
224}
225
226/* Find SIZE bytes of space in a heap.
227 Try to get them at ADDRESS (which must fall within some heap's range)
228 if we can get that many within one heap.
229
e429caa2 230 If enough space is not presently available in our reserve, this means
8e6208c5
KH
231 getting more page-aligned space from the system. If the returned space
232 is not contiguous to the last heap, allocate a new heap, and append it
abe9ff32
RS
233
234 obtain does not try to keep track of whether space is in use
235 or not in use. It just returns the address of SIZE bytes that
236 fall within a single heap. If you call obtain twice in a row
237 with the same arguments, you typically get the same value.
238 to the heap list. It's the caller's responsibility to keep
239 track of what space is in use.
dcfdbac7 240
e429caa2
KH
241 Return the address of the space if all went well, or zero if we couldn't
242 allocate the memory. */
abe9ff32 243
e429caa2
KH
244static POINTER
245obtain (address, size)
246 POINTER address;
247 SIZE size;
dcfdbac7 248{
e429caa2
KH
249 heap_ptr heap;
250 SIZE already_available;
dcfdbac7 251
abe9ff32 252 /* Find the heap that ADDRESS falls within. */
e429caa2 253 for (heap = last_heap; heap; heap = heap->prev)
dcfdbac7 254 {
e429caa2
KH
255 if (heap->start <= address && address <= heap->end)
256 break;
257 }
dcfdbac7 258
e429caa2 259 if (! heap)
abe9ff32 260 abort ();
dcfdbac7 261
abe9ff32
RS
262 /* If we can't fit SIZE bytes in that heap,
263 try successive later heaps. */
91a211b5 264 while (heap && (char *) address + size > (char *) heap->end)
e429caa2
KH
265 {
266 heap = heap->next;
267 if (heap == NIL_HEAP)
268 break;
269 address = heap->bloc_start;
dcfdbac7
JB
270 }
271
abe9ff32
RS
272 /* If we can't fit them within any existing heap,
273 get more space. */
e429caa2
KH
274 if (heap == NIL_HEAP)
275 {
276 POINTER new = (*real_morecore)(0);
277 SIZE get;
98b7fe02 278
e429caa2 279 already_available = (char *)last_heap->end - (char *)address;
dcfdbac7 280
e429caa2
KH
281 if (new != last_heap->end)
282 {
abe9ff32
RS
283 /* Someone else called sbrk. Make a new heap. */
284
285 heap_ptr new_heap = (heap_ptr) MEM_ROUNDUP (new);
286 POINTER bloc_start = (POINTER) MEM_ROUNDUP ((POINTER)(new_heap + 1));
e429caa2 287
91a211b5 288 if ((*real_morecore) ((char *) bloc_start - (char *) new) != new)
e429caa2
KH
289 return 0;
290
291 new_heap->start = new;
292 new_heap->end = bloc_start;
293 new_heap->bloc_start = bloc_start;
abe9ff32 294 new_heap->free = bloc_start;
e429caa2
KH
295 new_heap->next = NIL_HEAP;
296 new_heap->prev = last_heap;
47f13333
RS
297 new_heap->first_bloc = NIL_BLOC;
298 new_heap->last_bloc = NIL_BLOC;
e429caa2
KH
299 last_heap->next = new_heap;
300 last_heap = new_heap;
301
302 address = bloc_start;
303 already_available = 0;
304 }
dcfdbac7 305
abe9ff32
RS
306 /* Add space to the last heap (which we may have just created).
307 Get some extra, so we can come here less often. */
308
e429caa2 309 get = size + extra_bytes - already_available;
abe9ff32 310 get = (char *) ROUNDUP ((char *)last_heap->end + get)
e429caa2 311 - (char *) last_heap->end;
dcfdbac7 312
e429caa2
KH
313 if ((*real_morecore) (get) != last_heap->end)
314 return 0;
315
91a211b5 316 last_heap->end = (char *) last_heap->end + get;
e429caa2
KH
317 }
318
319 return address;
320}
dcfdbac7 321
abe9ff32
RS
322/* Return unused heap space to the system
323 if there is a lot of unused space now.
324 This can make the last heap smaller;
325 it can also eliminate the last heap entirely. */
326
dcfdbac7 327static void
e429caa2 328relinquish ()
dcfdbac7 329{
e429caa2 330 register heap_ptr h;
8d31e373 331 long excess = 0;
e429caa2 332
abe9ff32
RS
333 /* Add the amount of space beyond break_value
334 in all heaps which have extend beyond break_value at all. */
335
e429caa2
KH
336 for (h = last_heap; h && break_value < h->end; h = h->prev)
337 {
338 excess += (char *) h->end - (char *) ((break_value < h->bloc_start)
339 ? h->bloc_start : break_value);
340 }
341
342 if (excess > extra_bytes * 2 && (*real_morecore) (0) == last_heap->end)
dcfdbac7 343 {
7516b7d5
RS
344 /* Keep extra_bytes worth of empty space.
345 And don't free anything unless we can free at least extra_bytes. */
e429caa2 346 excess -= extra_bytes;
dcfdbac7 347
e429caa2
KH
348 if ((char *)last_heap->end - (char *)last_heap->bloc_start <= excess)
349 {
47f13333
RS
350 /* This heap should have no blocs in it. */
351 if (last_heap->first_bloc != NIL_BLOC
352 || last_heap->last_bloc != NIL_BLOC)
353 abort ();
354
abe9ff32 355 /* Return the last heap, with its header, to the system. */
e429caa2
KH
356 excess = (char *)last_heap->end - (char *)last_heap->start;
357 last_heap = last_heap->prev;
358 last_heap->next = NIL_HEAP;
359 }
360 else
361 {
362 excess = (char *) last_heap->end
abe9ff32 363 - (char *) ROUNDUP ((char *)last_heap->end - excess);
91a211b5 364 last_heap->end = (char *) last_heap->end - excess;
e429caa2 365 }
dcfdbac7 366
e429caa2 367 if ((*real_morecore) (- excess) == 0)
21532667
KH
368 {
369 /* If the system didn't want that much memory back, adjust
370 the end of the last heap to reflect that. This can occur
371 if break_value is still within the original data segment. */
91a211b5 372 last_heap->end = (char *) last_heap->end + excess;
21532667
KH
373 /* Make sure that the result of the adjustment is accurate.
374 It should be, for the else clause above; the other case,
375 which returns the entire last heap to the system, seems
376 unlikely to trigger this mode of failure. */
377 if (last_heap->end != (*real_morecore) (0))
378 abort ();
379 }
e429caa2 380 }
dcfdbac7 381}
719b242f
RS
382
383/* Return the total size in use by relocating allocator,
384 above where malloc gets space. */
385
386long
387r_alloc_size_in_use ()
388{
91a211b5 389 return (char *) break_value - (char *) virtual_break_value;
719b242f 390}
dcfdbac7 391\f
956ace37
JB
392/* The meat - allocating, freeing, and relocating blocs. */
393
956ace37 394/* Find the bloc referenced by the address in PTR. Returns a pointer
abe9ff32 395 to that block. */
dcfdbac7
JB
396
397static bloc_ptr
398find_bloc (ptr)
399 POINTER *ptr;
400{
401 register bloc_ptr p = first_bloc;
402
403 while (p != NIL_BLOC)
404 {
405 if (p->variable == ptr && p->data == *ptr)
406 return p;
407
408 p = p->next;
409 }
410
411 return p;
412}
413
414/* Allocate a bloc of SIZE bytes and append it to the chain of blocs.
98b7fe02
JB
415 Returns a pointer to the new bloc, or zero if we couldn't allocate
416 memory for the new block. */
dcfdbac7
JB
417
418static bloc_ptr
419get_bloc (size)
420 SIZE size;
421{
98b7fe02 422 register bloc_ptr new_bloc;
abe9ff32 423 register heap_ptr heap;
98b7fe02
JB
424
425 if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE))
e429caa2 426 || ! (new_bloc->data = obtain (break_value, size)))
98b7fe02 427 {
c2cd06e6 428 free (new_bloc);
98b7fe02
JB
429
430 return 0;
431 }
dcfdbac7 432
91a211b5 433 break_value = (char *) new_bloc->data + size;
e429caa2 434
dcfdbac7
JB
435 new_bloc->size = size;
436 new_bloc->next = NIL_BLOC;
8c7f1e35 437 new_bloc->variable = (POINTER *) NIL;
e429caa2 438 new_bloc->new_data = 0;
dcfdbac7 439
abe9ff32
RS
440 /* Record in the heap that this space is in use. */
441 heap = find_heap (new_bloc->data);
442 heap->free = break_value;
443
47f13333
RS
444 /* Maintain the correspondence between heaps and blocs. */
445 new_bloc->heap = heap;
446 heap->last_bloc = new_bloc;
447 if (heap->first_bloc == NIL_BLOC)
448 heap->first_bloc = new_bloc;
449
abe9ff32 450 /* Put this bloc on the doubly-linked list of blocs. */
dcfdbac7
JB
451 if (first_bloc)
452 {
453 new_bloc->prev = last_bloc;
454 last_bloc->next = new_bloc;
455 last_bloc = new_bloc;
456 }
457 else
458 {
459 first_bloc = last_bloc = new_bloc;
460 new_bloc->prev = NIL_BLOC;
461 }
462
463 return new_bloc;
464}
47f13333 465\f
abe9ff32
RS
466/* Calculate new locations of blocs in the list beginning with BLOC,
467 relocating it to start at ADDRESS, in heap HEAP. If enough space is
468 not presently available in our reserve, call obtain for
177c0ea7
JB
469 more space.
470
abe9ff32
RS
471 Store the new location of each bloc in its new_data field.
472 Do not touch the contents of blocs or break_value. */
dcfdbac7 473
e429caa2
KH
474static int
475relocate_blocs (bloc, heap, address)
476 bloc_ptr bloc;
477 heap_ptr heap;
478 POINTER address;
479{
480 register bloc_ptr b = bloc;
ad3bb3d2 481
49f82b3d 482 /* No need to ever call this if arena is frozen, bug somewhere! */
177c0ea7 483 if (r_alloc_freeze_level)
49f82b3d
RS
484 abort();
485
e429caa2
KH
486 while (b)
487 {
abe9ff32
RS
488 /* If bloc B won't fit within HEAP,
489 move to the next heap and try again. */
91a211b5 490 while (heap && (char *) address + b->size > (char *) heap->end)
e429caa2
KH
491 {
492 heap = heap->next;
493 if (heap == NIL_HEAP)
494 break;
495 address = heap->bloc_start;
496 }
dcfdbac7 497
abe9ff32
RS
498 /* If BLOC won't fit in any heap,
499 get enough new space to hold BLOC and all following blocs. */
e429caa2
KH
500 if (heap == NIL_HEAP)
501 {
502 register bloc_ptr tb = b;
503 register SIZE s = 0;
504
abe9ff32 505 /* Add up the size of all the following blocs. */
e429caa2
KH
506 while (tb != NIL_BLOC)
507 {
177c0ea7 508 if (tb->variable)
49f82b3d
RS
509 s += tb->size;
510
e429caa2
KH
511 tb = tb->next;
512 }
513
abe9ff32
RS
514 /* Get that space. */
515 address = obtain (address, s);
516 if (address == 0)
e429caa2
KH
517 return 0;
518
519 heap = last_heap;
520 }
521
abe9ff32
RS
522 /* Record the new address of this bloc
523 and update where the next bloc can start. */
e429caa2 524 b->new_data = address;
177c0ea7 525 if (b->variable)
91a211b5 526 address = (char *) address + b->size;
e429caa2
KH
527 b = b->next;
528 }
529
530 return 1;
531}
532
47f13333
RS
533/* Reorder the bloc BLOC to go before bloc BEFORE in the doubly linked list.
534 This is necessary if we put the memory of space of BLOC
535 before that of BEFORE. */
536
537static void
538reorder_bloc (bloc, before)
539 bloc_ptr bloc, before;
540{
541 bloc_ptr prev, next;
542
543 /* Splice BLOC out from where it is. */
544 prev = bloc->prev;
545 next = bloc->next;
546
547 if (prev)
548 prev->next = next;
549 if (next)
550 next->prev = prev;
551
552 /* Splice it in before BEFORE. */
553 prev = before->prev;
abe9ff32 554
47f13333
RS
555 if (prev)
556 prev->next = bloc;
557 bloc->prev = prev;
558
559 before->prev = bloc;
560 bloc->next = before;
561}
562\f
563/* Update the records of which heaps contain which blocs, starting
564 with heap HEAP and bloc BLOC. */
565
566static void
567update_heap_bloc_correspondence (bloc, heap)
abe9ff32
RS
568 bloc_ptr bloc;
569 heap_ptr heap;
570{
571 register bloc_ptr b;
572
47f13333
RS
573 /* Initialize HEAP's status to reflect blocs before BLOC. */
574 if (bloc != NIL_BLOC && bloc->prev != NIL_BLOC && bloc->prev->heap == heap)
575 {
576 /* The previous bloc is in HEAP. */
577 heap->last_bloc = bloc->prev;
91a211b5 578 heap->free = (char *) bloc->prev->data + bloc->prev->size;
47f13333
RS
579 }
580 else
581 {
582 /* HEAP contains no blocs before BLOC. */
583 heap->first_bloc = NIL_BLOC;
584 heap->last_bloc = NIL_BLOC;
585 heap->free = heap->bloc_start;
586 }
587
abe9ff32
RS
588 /* Advance through blocs one by one. */
589 for (b = bloc; b != NIL_BLOC; b = b->next)
590 {
47f13333
RS
591 /* Advance through heaps, marking them empty,
592 till we get to the one that B is in. */
abe9ff32
RS
593 while (heap)
594 {
595 if (heap->bloc_start <= b->data && b->data <= heap->end)
596 break;
597 heap = heap->next;
47f13333
RS
598 /* We know HEAP is not null now,
599 because there has to be space for bloc B. */
600 heap->first_bloc = NIL_BLOC;
601 heap->last_bloc = NIL_BLOC;
abe9ff32
RS
602 heap->free = heap->bloc_start;
603 }
47f13333
RS
604
605 /* Update HEAP's status for bloc B. */
91a211b5 606 heap->free = (char *) b->data + b->size;
47f13333
RS
607 heap->last_bloc = b;
608 if (heap->first_bloc == NIL_BLOC)
609 heap->first_bloc = b;
610
611 /* Record that B is in HEAP. */
612 b->heap = heap;
abe9ff32
RS
613 }
614
615 /* If there are any remaining heaps and no blocs left,
47f13333 616 mark those heaps as empty. */
abe9ff32
RS
617 heap = heap->next;
618 while (heap)
619 {
47f13333
RS
620 heap->first_bloc = NIL_BLOC;
621 heap->last_bloc = NIL_BLOC;
abe9ff32
RS
622 heap->free = heap->bloc_start;
623 heap = heap->next;
624 }
625}
47f13333 626\f
abe9ff32
RS
627/* Resize BLOC to SIZE bytes. This relocates the blocs
628 that come after BLOC in memory. */
629
e429caa2
KH
630static int
631resize_bloc (bloc, size)
632 bloc_ptr bloc;
633 SIZE size;
dcfdbac7 634{
e429caa2
KH
635 register bloc_ptr b;
636 heap_ptr heap;
637 POINTER address;
638 SIZE old_size;
639
49f82b3d 640 /* No need to ever call this if arena is frozen, bug somewhere! */
177c0ea7 641 if (r_alloc_freeze_level)
49f82b3d
RS
642 abort();
643
e429caa2
KH
644 if (bloc == NIL_BLOC || size == bloc->size)
645 return 1;
646
647 for (heap = first_heap; heap != NIL_HEAP; heap = heap->next)
648 {
649 if (heap->bloc_start <= bloc->data && bloc->data <= heap->end)
650 break;
651 }
652
653 if (heap == NIL_HEAP)
abe9ff32 654 abort ();
e429caa2
KH
655
656 old_size = bloc->size;
657 bloc->size = size;
658
abe9ff32 659 /* Note that bloc could be moved into the previous heap. */
91a211b5
GM
660 address = (bloc->prev ? (char *) bloc->prev->data + bloc->prev->size
661 : (char *) first_heap->bloc_start);
e429caa2
KH
662 while (heap)
663 {
664 if (heap->bloc_start <= address && address <= heap->end)
665 break;
666 heap = heap->prev;
667 }
668
669 if (! relocate_blocs (bloc, heap, address))
670 {
671 bloc->size = old_size;
672 return 0;
673 }
674
675 if (size > old_size)
676 {
677 for (b = last_bloc; b != bloc; b = b->prev)
678 {
49f82b3d
RS
679 if (!b->variable)
680 {
681 b->size = 0;
682 b->data = b->new_data;
177c0ea7
JB
683 }
684 else
49f82b3d
RS
685 {
686 safe_bcopy (b->data, b->new_data, b->size);
687 *b->variable = b->data = b->new_data;
688 }
689 }
690 if (!bloc->variable)
691 {
692 bloc->size = 0;
693 bloc->data = bloc->new_data;
694 }
695 else
696 {
697 safe_bcopy (bloc->data, bloc->new_data, old_size);
91a211b5 698 bzero ((char *) bloc->new_data + old_size, size - old_size);
49f82b3d 699 *bloc->variable = bloc->data = bloc->new_data;
e429caa2 700 }
e429caa2
KH
701 }
702 else
dcfdbac7 703 {
ad3bb3d2
JB
704 for (b = bloc; b != NIL_BLOC; b = b->next)
705 {
49f82b3d
RS
706 if (!b->variable)
707 {
708 b->size = 0;
709 b->data = b->new_data;
177c0ea7
JB
710 }
711 else
49f82b3d
RS
712 {
713 safe_bcopy (b->data, b->new_data, b->size);
714 *b->variable = b->data = b->new_data;
715 }
ad3bb3d2 716 }
ad3bb3d2 717 }
dcfdbac7 718
47f13333 719 update_heap_bloc_correspondence (bloc, heap);
abe9ff32 720
91a211b5
GM
721 break_value = (last_bloc ? (char *) last_bloc->data + last_bloc->size
722 : (char *) first_heap->bloc_start);
e429caa2
KH
723 return 1;
724}
47f13333 725\f
abe9ff32
RS
726/* Free BLOC from the chain of blocs, relocating any blocs above it.
727 This may return space to the system. */
dcfdbac7
JB
728
729static void
730free_bloc (bloc)
731 bloc_ptr bloc;
732{
47f13333
RS
733 heap_ptr heap = bloc->heap;
734
49f82b3d
RS
735 if (r_alloc_freeze_level)
736 {
737 bloc->variable = (POINTER *) NIL;
738 return;
739 }
177c0ea7 740
e429caa2
KH
741 resize_bloc (bloc, 0);
742
dcfdbac7
JB
743 if (bloc == first_bloc && bloc == last_bloc)
744 {
745 first_bloc = last_bloc = NIL_BLOC;
746 }
747 else if (bloc == last_bloc)
748 {
749 last_bloc = bloc->prev;
750 last_bloc->next = NIL_BLOC;
751 }
752 else if (bloc == first_bloc)
753 {
754 first_bloc = bloc->next;
755 first_bloc->prev = NIL_BLOC;
dcfdbac7
JB
756 }
757 else
758 {
759 bloc->next->prev = bloc->prev;
760 bloc->prev->next = bloc->next;
dcfdbac7
JB
761 }
762
47f13333
RS
763 /* Update the records of which blocs are in HEAP. */
764 if (heap->first_bloc == bloc)
765 {
d5179acc 766 if (bloc->next != 0 && bloc->next->heap == heap)
47f13333
RS
767 heap->first_bloc = bloc->next;
768 else
769 heap->first_bloc = heap->last_bloc = NIL_BLOC;
770 }
771 if (heap->last_bloc == bloc)
772 {
d5179acc 773 if (bloc->prev != 0 && bloc->prev->heap == heap)
47f13333
RS
774 heap->last_bloc = bloc->prev;
775 else
776 heap->first_bloc = heap->last_bloc = NIL_BLOC;
777 }
778
e429caa2 779 relinquish ();
dcfdbac7
JB
780 free (bloc);
781}
782\f
956ace37
JB
783/* Interface routines. */
784
98b7fe02 785/* Obtain SIZE bytes of storage from the free pool, or the system, as
2c46d29f 786 necessary. If relocatable blocs are in use, this means relocating
98b7fe02
JB
787 them. This function gets plugged into the GNU malloc's __morecore
788 hook.
789
7516b7d5
RS
790 We provide hysteresis, never relocating by less than extra_bytes.
791
98b7fe02
JB
792 If we're out of memory, we should return zero, to imitate the other
793 __morecore hook values - in particular, __default_morecore in the
794 GNU malloc package. */
dcfdbac7 795
177c0ea7 796POINTER
dcfdbac7
JB
797r_alloc_sbrk (size)
798 long size;
799{
e429caa2
KH
800 register bloc_ptr b;
801 POINTER address;
dcfdbac7 802
44d3dec0
RS
803 if (! r_alloc_initialized)
804 r_alloc_init ();
805
dcfdbac7 806 if (! use_relocatable_buffers)
bbc60227 807 return (*real_morecore) (size);
dcfdbac7 808
e429caa2
KH
809 if (size == 0)
810 return virtual_break_value;
7516b7d5 811
e429caa2 812 if (size > 0)
dcfdbac7 813 {
abe9ff32
RS
814 /* Allocate a page-aligned space. GNU malloc would reclaim an
815 extra space if we passed an unaligned one. But we could
8e6208c5 816 not always find a space which is contiguous to the previous. */
e429caa2
KH
817 POINTER new_bloc_start;
818 heap_ptr h = first_heap;
abe9ff32 819 SIZE get = ROUNDUP (size);
7516b7d5 820
abe9ff32 821 address = (POINTER) ROUNDUP (virtual_break_value);
e429caa2 822
abe9ff32
RS
823 /* Search the list upward for a heap which is large enough. */
824 while ((char *) h->end < (char *) MEM_ROUNDUP ((char *)address + get))
e429caa2
KH
825 {
826 h = h->next;
827 if (h == NIL_HEAP)
828 break;
abe9ff32 829 address = (POINTER) ROUNDUP (h->start);
e429caa2
KH
830 }
831
abe9ff32 832 /* If not found, obtain more space. */
e429caa2
KH
833 if (h == NIL_HEAP)
834 {
835 get += extra_bytes + page_size;
836
49f82b3d 837 if (! obtain (address, get))
e429caa2 838 return 0;
98b7fe02 839
e429caa2 840 if (first_heap == last_heap)
abe9ff32 841 address = (POINTER) ROUNDUP (virtual_break_value);
e429caa2 842 else
abe9ff32 843 address = (POINTER) ROUNDUP (last_heap->start);
e429caa2
KH
844 h = last_heap;
845 }
846
abe9ff32 847 new_bloc_start = (POINTER) MEM_ROUNDUP ((char *)address + get);
e429caa2
KH
848
849 if (first_heap->bloc_start < new_bloc_start)
850 {
49f82b3d 851 /* This is no clean solution - no idea how to do it better. */
177c0ea7 852 if (r_alloc_freeze_level)
49f82b3d
RS
853 return NIL;
854
855 /* There is a bug here: if the above obtain call succeeded, but the
856 relocate_blocs call below does not succeed, we need to free
857 the memory that we got with obtain. */
858
abe9ff32 859 /* Move all blocs upward. */
49f82b3d 860 if (! relocate_blocs (first_bloc, h, new_bloc_start))
e429caa2
KH
861 return 0;
862
863 /* Note that (POINTER)(h+1) <= new_bloc_start since
864 get >= page_size, so the following does not destroy the heap
abe9ff32 865 header. */
e429caa2
KH
866 for (b = last_bloc; b != NIL_BLOC; b = b->prev)
867 {
868 safe_bcopy (b->data, b->new_data, b->size);
869 *b->variable = b->data = b->new_data;
870 }
871
872 h->bloc_start = new_bloc_start;
abe9ff32 873
47f13333 874 update_heap_bloc_correspondence (first_bloc, h);
e429caa2 875 }
e429caa2
KH
876 if (h != first_heap)
877 {
878 /* Give up managing heaps below the one the new
abe9ff32 879 virtual_break_value points to. */
e429caa2
KH
880 first_heap->prev = NIL_HEAP;
881 first_heap->next = h->next;
882 first_heap->start = h->start;
883 first_heap->end = h->end;
abe9ff32 884 first_heap->free = h->free;
47f13333
RS
885 first_heap->first_bloc = h->first_bloc;
886 first_heap->last_bloc = h->last_bloc;
e429caa2
KH
887 first_heap->bloc_start = h->bloc_start;
888
889 if (first_heap->next)
890 first_heap->next->prev = first_heap;
891 else
892 last_heap = first_heap;
893 }
894
895 bzero (address, size);
dcfdbac7 896 }
e429caa2 897 else /* size < 0 */
dcfdbac7 898 {
e429caa2
KH
899 SIZE excess = (char *)first_heap->bloc_start
900 - ((char *)virtual_break_value + size);
901
902 address = virtual_break_value;
903
904 if (r_alloc_freeze_level == 0 && excess > 2 * extra_bytes)
905 {
906 excess -= extra_bytes;
907 first_heap->bloc_start
47f13333 908 = (POINTER) MEM_ROUNDUP ((char *)first_heap->bloc_start - excess);
e429caa2 909
abe9ff32 910 relocate_blocs (first_bloc, first_heap, first_heap->bloc_start);
7516b7d5 911
e429caa2
KH
912 for (b = first_bloc; b != NIL_BLOC; b = b->next)
913 {
914 safe_bcopy (b->data, b->new_data, b->size);
915 *b->variable = b->data = b->new_data;
916 }
917 }
918
919 if ((char *)virtual_break_value + size < (char *)first_heap->start)
920 {
921 /* We found an additional space below the first heap */
922 first_heap->start = (POINTER) ((char *)virtual_break_value + size);
923 }
dcfdbac7
JB
924 }
925
e429caa2 926 virtual_break_value = (POINTER) ((char *)address + size);
47f13333 927 break_value = (last_bloc
91a211b5
GM
928 ? (char *) last_bloc->data + last_bloc->size
929 : (char *) first_heap->bloc_start);
e429caa2 930 if (size < 0)
abe9ff32 931 relinquish ();
7516b7d5 932
e429caa2 933 return address;
dcfdbac7
JB
934}
935
0a58f946 936
dcfdbac7
JB
937/* Allocate a relocatable bloc of storage of size SIZE. A pointer to
938 the data is returned in *PTR. PTR is thus the address of some variable
98b7fe02
JB
939 which will use the data area.
940
49f82b3d
RS
941 The allocation of 0 bytes is valid.
942 In case r_alloc_freeze is set, a best fit of unused blocs could be done
943 before allocating a new area. Not yet done.
944
98b7fe02
JB
945 If we can't allocate the necessary memory, set *PTR to zero, and
946 return zero. */
dcfdbac7
JB
947
948POINTER
949r_alloc (ptr, size)
950 POINTER *ptr;
951 SIZE size;
952{
953 register bloc_ptr new_bloc;
954
2c46d29f
RS
955 if (! r_alloc_initialized)
956 r_alloc_init ();
957
abe9ff32 958 new_bloc = get_bloc (MEM_ROUNDUP (size));
98b7fe02
JB
959 if (new_bloc)
960 {
961 new_bloc->variable = ptr;
962 *ptr = new_bloc->data;
963 }
964 else
965 *ptr = 0;
dcfdbac7
JB
966
967 return *ptr;
968}
969
2c46d29f
RS
970/* Free a bloc of relocatable storage whose data is pointed to by PTR.
971 Store 0 in *PTR to show there's no block allocated. */
dcfdbac7
JB
972
973void
974r_alloc_free (ptr)
975 register POINTER *ptr;
976{
977 register bloc_ptr dead_bloc;
978
44d3dec0
RS
979 if (! r_alloc_initialized)
980 r_alloc_init ();
981
dcfdbac7
JB
982 dead_bloc = find_bloc (ptr);
983 if (dead_bloc == NIL_BLOC)
984 abort ();
985
986 free_bloc (dead_bloc);
2c46d29f 987 *ptr = 0;
719b242f 988
d5179acc 989#ifdef emacs
719b242f 990 refill_memory_reserve ();
d5179acc 991#endif
dcfdbac7
JB
992}
993
16a5c729 994/* Given a pointer at address PTR to relocatable data, resize it to SIZE.
98b7fe02
JB
995 Do this by shifting all blocks above this one up in memory, unless
996 SIZE is less than or equal to the current bloc size, in which case
997 do nothing.
dcfdbac7 998
49f82b3d 999 In case r_alloc_freeze is set, a new bloc is allocated, and the
8e6208c5 1000 memory copied to it. Not very efficient. We could traverse the
49f82b3d
RS
1001 bloc_list for a best fit of free blocs first.
1002
98b7fe02
JB
1003 Change *PTR to reflect the new bloc, and return this value.
1004
1005 If more memory cannot be allocated, then leave *PTR unchanged, and
1006 return zero. */
dcfdbac7
JB
1007
1008POINTER
1009r_re_alloc (ptr, size)
1010 POINTER *ptr;
1011 SIZE size;
1012{
16a5c729 1013 register bloc_ptr bloc;
dcfdbac7 1014
44d3dec0
RS
1015 if (! r_alloc_initialized)
1016 r_alloc_init ();
1017
49f82b3d
RS
1018 if (!*ptr)
1019 return r_alloc (ptr, size);
177c0ea7 1020 if (!size)
49f82b3d
RS
1021 {
1022 r_alloc_free (ptr);
1023 return r_alloc (ptr, 0);
1024 }
1025
16a5c729
JB
1026 bloc = find_bloc (ptr);
1027 if (bloc == NIL_BLOC)
dcfdbac7
JB
1028 abort ();
1029
177c0ea7 1030 if (size < bloc->size)
49f82b3d
RS
1031 {
1032 /* Wouldn't it be useful to actually resize the bloc here? */
1033 /* I think so too, but not if it's too expensive... */
177c0ea7
JB
1034 if ((bloc->size - MEM_ROUNDUP (size) >= page_size)
1035 && r_alloc_freeze_level == 0)
49f82b3d
RS
1036 {
1037 resize_bloc (bloc, MEM_ROUNDUP (size));
1038 /* Never mind if this fails, just do nothing... */
1039 /* It *should* be infallible! */
1040 }
1041 }
1042 else if (size > bloc->size)
1043 {
1044 if (r_alloc_freeze_level)
1045 {
1046 bloc_ptr new_bloc;
1047 new_bloc = get_bloc (MEM_ROUNDUP (size));
1048 if (new_bloc)
1049 {
1050 new_bloc->variable = ptr;
1051 *ptr = new_bloc->data;
1052 bloc->variable = (POINTER *) NIL;
1053 }
1054 else
1055 return NIL;
1056 }
177c0ea7 1057 else
49f82b3d
RS
1058 {
1059 if (! resize_bloc (bloc, MEM_ROUNDUP (size)))
1060 return NIL;
1061 }
1062 }
dcfdbac7
JB
1063 return *ptr;
1064}
81bd58e8
KH
1065
1066/* Disable relocations, after making room for at least SIZE bytes
1067 of non-relocatable heap if possible. The relocatable blocs are
1068 guaranteed to hold still until thawed, even if this means that
1069 malloc must return a null pointer. */
abe9ff32 1070
81bd58e8
KH
1071void
1072r_alloc_freeze (size)
1073 long size;
1074{
44d3dec0
RS
1075 if (! r_alloc_initialized)
1076 r_alloc_init ();
1077
81bd58e8
KH
1078 /* If already frozen, we can't make any more room, so don't try. */
1079 if (r_alloc_freeze_level > 0)
1080 size = 0;
1081 /* If we can't get the amount requested, half is better than nothing. */
1082 while (size > 0 && r_alloc_sbrk (size) == 0)
1083 size /= 2;
1084 ++r_alloc_freeze_level;
1085 if (size > 0)
1086 r_alloc_sbrk (-size);
1087}
1088
1089void
1090r_alloc_thaw ()
1091{
49f82b3d 1092
177c0ea7 1093 if (! r_alloc_initialized)
49f82b3d
RS
1094 r_alloc_init ();
1095
81bd58e8
KH
1096 if (--r_alloc_freeze_level < 0)
1097 abort ();
49f82b3d 1098
177c0ea7
JB
1099 /* This frees all unused blocs. It is not too inefficient, as the resize
1100 and bcopy is done only once. Afterwards, all unreferenced blocs are
49f82b3d 1101 already shrunk to zero size. */
177c0ea7 1102 if (!r_alloc_freeze_level)
49f82b3d
RS
1103 {
1104 bloc_ptr *b = &first_bloc;
177c0ea7
JB
1105 while (*b)
1106 if (!(*b)->variable)
1107 free_bloc (*b);
1108 else
49f82b3d
RS
1109 b = &(*b)->next;
1110 }
81bd58e8 1111}
49f82b3d 1112
dec41418
RS
1113
1114#if defined (emacs) && defined (DOUG_LEA_MALLOC)
1115
1116/* Reinitialize the morecore hook variables after restarting a dumped
1117 Emacs. This is needed when using Doug Lea's malloc from GNU libc. */
1118void
1119r_alloc_reinit ()
1120{
1121 /* Only do this if the hook has been reset, so that we don't get an
1122 infinite loop, in case Emacs was linked statically. */
1123 if (__morecore != r_alloc_sbrk)
1124 {
1125 real_morecore = __morecore;
1126 __morecore = r_alloc_sbrk;
1127 }
1128}
0a58f946
GM
1129
1130#endif /* emacs && DOUG_LEA_MALLOC */
dec41418 1131
e429caa2 1132#ifdef DEBUG
0a58f946 1133
e429caa2
KH
1134#include <assert.h>
1135
44d3dec0 1136void
e429caa2
KH
1137r_alloc_check ()
1138{
6d16dd06
RS
1139 int found = 0;
1140 heap_ptr h, ph = 0;
1141 bloc_ptr b, pb = 0;
1142
1143 if (!r_alloc_initialized)
1144 return;
1145
1146 assert (first_heap);
1147 assert (last_heap->end <= (POINTER) sbrk (0));
1148 assert ((POINTER) first_heap < first_heap->start);
1149 assert (first_heap->start <= virtual_break_value);
1150 assert (virtual_break_value <= first_heap->end);
1151
1152 for (h = first_heap; h; h = h->next)
1153 {
1154 assert (h->prev == ph);
1155 assert ((POINTER) ROUNDUP (h->end) == h->end);
40f3f04b
RS
1156#if 0 /* ??? The code in ralloc.c does not really try to ensure
1157 the heap start has any sort of alignment.
1158 Perhaps it should. */
6d16dd06 1159 assert ((POINTER) MEM_ROUNDUP (h->start) == h->start);
40f3f04b 1160#endif
6d16dd06
RS
1161 assert ((POINTER) MEM_ROUNDUP (h->bloc_start) == h->bloc_start);
1162 assert (h->start <= h->bloc_start && h->bloc_start <= h->end);
1163
1164 if (ph)
1165 {
1166 assert (ph->end < h->start);
1167 assert (h->start <= (POINTER)h && (POINTER)(h+1) <= h->bloc_start);
1168 }
1169
1170 if (h->bloc_start <= break_value && break_value <= h->end)
1171 found = 1;
1172
1173 ph = h;
1174 }
1175
1176 assert (found);
1177 assert (last_heap == ph);
1178
1179 for (b = first_bloc; b; b = b->next)
1180 {
1181 assert (b->prev == pb);
1182 assert ((POINTER) MEM_ROUNDUP (b->data) == b->data);
1183 assert ((SIZE) MEM_ROUNDUP (b->size) == b->size);
1184
1185 ph = 0;
1186 for (h = first_heap; h; h = h->next)
1187 {
1188 if (h->bloc_start <= b->data && b->data + b->size <= h->end)
1189 break;
1190 ph = h;
1191 }
1192
1193 assert (h);
1194
1195 if (pb && pb->data + pb->size != b->data)
1196 {
1197 assert (ph && b->data == h->bloc_start);
1198 while (ph)
1199 {
1200 if (ph->bloc_start <= pb->data
1201 && pb->data + pb->size <= ph->end)
1202 {
1203 assert (pb->data + pb->size + b->size > ph->end);
1204 break;
1205 }
1206 else
1207 {
1208 assert (ph->bloc_start + b->size > ph->end);
1209 }
1210 ph = ph->prev;
1211 }
1212 }
1213 pb = b;
1214 }
1215
1216 assert (last_bloc == pb);
1217
1218 if (last_bloc)
1219 assert (last_bloc->data + last_bloc->size == break_value);
1220 else
1221 assert (first_heap->bloc_start == break_value);
e429caa2 1222}
0a58f946 1223
e429caa2 1224#endif /* DEBUG */
0a58f946 1225
0a58f946
GM
1226
1227\f
1228/***********************************************************************
1229 Initialization
1230 ***********************************************************************/
1231
0a58f946
GM
1232/* Initialize various things for memory allocation. */
1233
1234static void
1235r_alloc_init ()
1236{
1237 if (r_alloc_initialized)
1238 return;
0a58f946 1239 r_alloc_initialized = 1;
177c0ea7 1240
a2c23c92
DL
1241 page_size = PAGE;
1242#ifndef SYSTEM_MALLOC
0a58f946
GM
1243 real_morecore = __morecore;
1244 __morecore = r_alloc_sbrk;
1245
1246 first_heap = last_heap = &heap_base;
1247 first_heap->next = first_heap->prev = NIL_HEAP;
1248 first_heap->start = first_heap->bloc_start
1249 = virtual_break_value = break_value = (*real_morecore) (0);
1250 if (break_value == NIL)
1251 abort ();
1252
0a58f946 1253 extra_bytes = ROUNDUP (50000);
a2c23c92 1254#endif
0a58f946
GM
1255
1256#ifdef DOUG_LEA_MALLOC
1673df2e
JD
1257 BLOCK_INPUT;
1258 mallopt (M_TOP_PAD, 64 * 4096);
1259 UNBLOCK_INPUT;
0a58f946 1260#else
a2c23c92 1261#ifndef SYSTEM_MALLOC
0a58f946
GM
1262 /* Give GNU malloc's morecore some hysteresis
1263 so that we move all the relocatable blocks much less often. */
1264 __malloc_extra_blocks = 64;
1265#endif
a2c23c92 1266#endif
0a58f946 1267
5ad25b24 1268#ifndef SYSTEM_MALLOC
0a58f946
GM
1269 first_heap->end = (POINTER) ROUNDUP (first_heap->start);
1270
1271 /* The extra call to real_morecore guarantees that the end of the
1272 address space is a multiple of page_size, even if page_size is
1273 not really the page size of the system running the binary in
1274 which page_size is stored. This allows a binary to be built on a
1275 system with one page size and run on a system with a smaller page
1276 size. */
91a211b5 1277 (*real_morecore) ((char *) first_heap->end - (char *) first_heap->start);
0a58f946
GM
1278
1279 /* Clear the rest of the last page; this memory is in our address space
1280 even though it is after the sbrk value. */
1281 /* Doubly true, with the additional call that explicitly adds the
1282 rest of that page to the address space. */
91a211b5
GM
1283 bzero (first_heap->start,
1284 (char *) first_heap->end - (char *) first_heap->start);
0a58f946 1285 virtual_break_value = break_value = first_heap->bloc_start = first_heap->end;
a2c23c92 1286#endif
177c0ea7 1287
0a58f946
GM
1288 use_relocatable_buffers = 1;
1289}
ab5796a9
MB
1290
1291/* arch-tag: 6a524a15-faff-44c8-95d4-a5da6f55110f
1292 (do not change this comment) */