1 |
/* Block-relocating memory allocator. |
/* Block-relocating memory allocator. |
2 |
Copyright (C) 1993, 1995, 2000 Free Software Foundation, Inc. |
Copyright (C) 1993, 1995, 2000 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Emacs. |
This file is part of GNU Emacs. |
42 |
extern void safe_bcopy (); |
extern void safe_bcopy (); |
43 |
|
|
44 |
#ifdef DOUG_LEA_MALLOC |
#ifdef DOUG_LEA_MALLOC |
45 |
#define M_TOP_PAD -2 |
#define M_TOP_PAD -2 |
46 |
extern int mallopt (); |
extern int mallopt (); |
47 |
#else /* not DOUG_LEA_MALLOC */ |
#else /* not DOUG_LEA_MALLOC */ |
48 |
#ifndef SYSTEM_MALLOC |
#ifndef SYSTEM_MALLOC |
98 |
/* This is the size of a page. We round memory requests to this boundary. */ |
/* This is the size of a page. We round memory requests to this boundary. */ |
99 |
static int page_size; |
static int page_size; |
100 |
|
|
101 |
/* Whenever we get memory from the system, get this many extra bytes. This |
/* Whenever we get memory from the system, get this many extra bytes. This |
102 |
must be a multiple of page_size. */ |
must be a multiple of page_size. */ |
103 |
static int extra_bytes; |
static int extra_bytes; |
104 |
|
|
141 |
We try to make just one heap and make it larger as necessary. |
We try to make just one heap and make it larger as necessary. |
142 |
But sometimes we can't do that, because we can't get contiguous |
But sometimes we can't do that, because we can't get contiguous |
143 |
space to add onto the heap. When that happens, we start a new heap. */ |
space to add onto the heap. When that happens, we start a new heap. */ |
144 |
|
|
145 |
typedef struct heap |
typedef struct heap |
146 |
{ |
{ |
147 |
struct heap *next; |
struct heap *next; |
174 |
/* These structures are allocated in the malloc arena. |
/* These structures are allocated in the malloc arena. |
175 |
The linked list is kept in order of increasing '.data' members. |
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 |
The data blocks abut each other; if b->next is non-nil, then |
177 |
b->data + b->size == b->next->data. |
b->data + b->size == b->next->data. |
178 |
|
|
179 |
An element with variable==NIL denotes a freed block, which has not yet |
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 |
been collected. They may only appear while r_alloc_freeze > 0, and will be |
467 |
/* Calculate new locations of blocs in the list beginning with BLOC, |
/* Calculate new locations of blocs in the list beginning with BLOC, |
468 |
relocating it to start at ADDRESS, in heap HEAP. If enough space is |
relocating it to start at ADDRESS, in heap HEAP. If enough space is |
469 |
not presently available in our reserve, call obtain for |
not presently available in our reserve, call obtain for |
470 |
more space. |
more space. |
471 |
|
|
472 |
Store the new location of each bloc in its new_data field. |
Store the new location of each bloc in its new_data field. |
473 |
Do not touch the contents of blocs or break_value. */ |
Do not touch the contents of blocs or break_value. */ |
474 |
|
|
481 |
register bloc_ptr b = bloc; |
register bloc_ptr b = bloc; |
482 |
|
|
483 |
/* No need to ever call this if arena is frozen, bug somewhere! */ |
/* No need to ever call this if arena is frozen, bug somewhere! */ |
484 |
if (r_alloc_freeze_level) |
if (r_alloc_freeze_level) |
485 |
abort(); |
abort(); |
486 |
|
|
487 |
while (b) |
while (b) |
506 |
/* Add up the size of all the following blocs. */ |
/* Add up the size of all the following blocs. */ |
507 |
while (tb != NIL_BLOC) |
while (tb != NIL_BLOC) |
508 |
{ |
{ |
509 |
if (tb->variable) |
if (tb->variable) |
510 |
s += tb->size; |
s += tb->size; |
511 |
|
|
512 |
tb = tb->next; |
tb = tb->next; |
523 |
/* Record the new address of this bloc |
/* Record the new address of this bloc |
524 |
and update where the next bloc can start. */ |
and update where the next bloc can start. */ |
525 |
b->new_data = address; |
b->new_data = address; |
526 |
if (b->variable) |
if (b->variable) |
527 |
address = (char *) address + b->size; |
address = (char *) address + b->size; |
528 |
b = b->next; |
b = b->next; |
529 |
} |
} |
639 |
SIZE old_size; |
SIZE old_size; |
640 |
|
|
641 |
/* No need to ever call this if arena is frozen, bug somewhere! */ |
/* No need to ever call this if arena is frozen, bug somewhere! */ |
642 |
if (r_alloc_freeze_level) |
if (r_alloc_freeze_level) |
643 |
abort(); |
abort(); |
644 |
|
|
645 |
if (bloc == NIL_BLOC || size == bloc->size) |
if (bloc == NIL_BLOC || size == bloc->size) |
681 |
{ |
{ |
682 |
b->size = 0; |
b->size = 0; |
683 |
b->data = b->new_data; |
b->data = b->new_data; |
684 |
} |
} |
685 |
else |
else |
686 |
{ |
{ |
687 |
safe_bcopy (b->data, b->new_data, b->size); |
safe_bcopy (b->data, b->new_data, b->size); |
688 |
*b->variable = b->data = b->new_data; |
*b->variable = b->data = b->new_data; |
708 |
{ |
{ |
709 |
b->size = 0; |
b->size = 0; |
710 |
b->data = b->new_data; |
b->data = b->new_data; |
711 |
} |
} |
712 |
else |
else |
713 |
{ |
{ |
714 |
safe_bcopy (b->data, b->new_data, b->size); |
safe_bcopy (b->data, b->new_data, b->size); |
715 |
*b->variable = b->data = b->new_data; |
*b->variable = b->data = b->new_data; |
738 |
bloc->variable = (POINTER *) NIL; |
bloc->variable = (POINTER *) NIL; |
739 |
return; |
return; |
740 |
} |
} |
741 |
|
|
742 |
resize_bloc (bloc, 0); |
resize_bloc (bloc, 0); |
743 |
|
|
744 |
if (bloc == first_bloc && bloc == last_bloc) |
if (bloc == first_bloc && bloc == last_bloc) |
794 |
__morecore hook values - in particular, __default_morecore in the |
__morecore hook values - in particular, __default_morecore in the |
795 |
GNU malloc package. */ |
GNU malloc package. */ |
796 |
|
|
797 |
POINTER |
POINTER |
798 |
r_alloc_sbrk (size) |
r_alloc_sbrk (size) |
799 |
long size; |
long size; |
800 |
{ |
{ |
850 |
if (first_heap->bloc_start < new_bloc_start) |
if (first_heap->bloc_start < new_bloc_start) |
851 |
{ |
{ |
852 |
/* This is no clean solution - no idea how to do it better. */ |
/* This is no clean solution - no idea how to do it better. */ |
853 |
if (r_alloc_freeze_level) |
if (r_alloc_freeze_level) |
854 |
return NIL; |
return NIL; |
855 |
|
|
856 |
/* There is a bug here: if the above obtain call succeeded, but the |
/* There is a bug here: if the above obtain call succeeded, but the |
1018 |
|
|
1019 |
if (!*ptr) |
if (!*ptr) |
1020 |
return r_alloc (ptr, size); |
return r_alloc (ptr, size); |
1021 |
if (!size) |
if (!size) |
1022 |
{ |
{ |
1023 |
r_alloc_free (ptr); |
r_alloc_free (ptr); |
1024 |
return r_alloc (ptr, 0); |
return r_alloc (ptr, 0); |
1028 |
if (bloc == NIL_BLOC) |
if (bloc == NIL_BLOC) |
1029 |
abort (); |
abort (); |
1030 |
|
|
1031 |
if (size < bloc->size) |
if (size < bloc->size) |
1032 |
{ |
{ |
1033 |
/* Wouldn't it be useful to actually resize the bloc here? */ |
/* Wouldn't it be useful to actually resize the bloc here? */ |
1034 |
/* I think so too, but not if it's too expensive... */ |
/* I think so too, but not if it's too expensive... */ |
1035 |
if ((bloc->size - MEM_ROUNDUP (size) >= page_size) |
if ((bloc->size - MEM_ROUNDUP (size) >= page_size) |
1036 |
&& r_alloc_freeze_level == 0) |
&& r_alloc_freeze_level == 0) |
1037 |
{ |
{ |
1038 |
resize_bloc (bloc, MEM_ROUNDUP (size)); |
resize_bloc (bloc, MEM_ROUNDUP (size)); |
1039 |
/* Never mind if this fails, just do nothing... */ |
/* Never mind if this fails, just do nothing... */ |
1055 |
else |
else |
1056 |
return NIL; |
return NIL; |
1057 |
} |
} |
1058 |
else |
else |
1059 |
{ |
{ |
1060 |
if (! resize_bloc (bloc, MEM_ROUNDUP (size))) |
if (! resize_bloc (bloc, MEM_ROUNDUP (size))) |
1061 |
return NIL; |
return NIL; |
1091 |
r_alloc_thaw () |
r_alloc_thaw () |
1092 |
{ |
{ |
1093 |
|
|
1094 |
if (! r_alloc_initialized) |
if (! r_alloc_initialized) |
1095 |
r_alloc_init (); |
r_alloc_init (); |
1096 |
|
|
1097 |
if (--r_alloc_freeze_level < 0) |
if (--r_alloc_freeze_level < 0) |
1098 |
abort (); |
abort (); |
1099 |
|
|
1100 |
/* This frees all unused blocs. It is not too inefficient, as the resize |
/* This frees all unused blocs. It is not too inefficient, as the resize |
1101 |
and bcopy is done only once. Afterwards, all unreferenced blocs are |
and bcopy is done only once. Afterwards, all unreferenced blocs are |
1102 |
already shrunk to zero size. */ |
already shrunk to zero size. */ |
1103 |
if (!r_alloc_freeze_level) |
if (!r_alloc_freeze_level) |
1104 |
{ |
{ |
1105 |
bloc_ptr *b = &first_bloc; |
bloc_ptr *b = &first_bloc; |
1106 |
while (*b) |
while (*b) |
1107 |
if (!(*b)->variable) |
if (!(*b)->variable) |
1108 |
free_bloc (*b); |
free_bloc (*b); |
1109 |
else |
else |
1110 |
b = &(*b)->next; |
b = &(*b)->next; |
1111 |
} |
} |
1112 |
} |
} |
1238 |
if (r_alloc_initialized) |
if (r_alloc_initialized) |
1239 |
return; |
return; |
1240 |
r_alloc_initialized = 1; |
r_alloc_initialized = 1; |
1241 |
|
|
1242 |
page_size = PAGE; |
page_size = PAGE; |
1243 |
#ifndef SYSTEM_MALLOC |
#ifndef SYSTEM_MALLOC |
1244 |
real_morecore = __morecore; |
real_morecore = __morecore; |
1283 |
(char *) first_heap->end - (char *) first_heap->start); |
(char *) first_heap->end - (char *) first_heap->start); |
1284 |
virtual_break_value = break_value = first_heap->bloc_start = first_heap->end; |
virtual_break_value = break_value = first_heap->bloc_start = first_heap->end; |
1285 |
#endif |
#endif |
1286 |
|
|
1287 |
use_relocatable_buffers = 1; |
use_relocatable_buffers = 1; |
1288 |
} |
} |