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