Applied François' patch to be able to free large allocations. Even though the
heap is going away soon, it doesn't hurt to have it in the repository. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22457 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -73,6 +73,10 @@ struct heap_page {
|
|||||||
uint16 in_use : 1;
|
uint16 in_use : 1;
|
||||||
} PACKED;
|
} PACKED;
|
||||||
|
|
||||||
|
// used for bin==bin_count allocations
|
||||||
|
#define allocation_id free_count
|
||||||
|
|
||||||
|
static vint32 current_alloc_id = 0;
|
||||||
static struct heap_page *heap_alloc_table;
|
static struct heap_page *heap_alloc_table;
|
||||||
static addr_t heap_base_ptr;
|
static addr_t heap_base_ptr;
|
||||||
static addr_t heap_base;
|
static addr_t heap_base;
|
||||||
@@ -367,6 +371,13 @@ heap_init_post_thread(kernel_args *args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int32
|
||||||
|
next_alloc_id(void)
|
||||||
|
{
|
||||||
|
return atomic_add(¤t_alloc_id, 1) & ((1<<(9-1))-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
raw_alloc(unsigned int size, int bin_index)
|
raw_alloc(unsigned int size, int bin_index)
|
||||||
{
|
{
|
||||||
@@ -451,9 +462,37 @@ memalign(size_t alignment, size_t size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (bin_index == bin_count) {
|
if (bin_index == bin_count) {
|
||||||
|
int32 alloc_id;
|
||||||
|
alloc_id = next_alloc_id();
|
||||||
|
|
||||||
|
// try to find freed blocks first...
|
||||||
|
if (size < (heap_base_ptr - heap_base) / 10) { // but don't try too hard
|
||||||
|
int first = -1;
|
||||||
|
page = heap_alloc_table;
|
||||||
|
for (i = 0; i < (heap_base_ptr-heap_base)/B_PAGE_SIZE; i++) {
|
||||||
|
if (page[i].in_use) {
|
||||||
|
first = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first > 0) {
|
||||||
|
if ((1 + i - first)*B_PAGE_SIZE > size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first = i;
|
||||||
|
}
|
||||||
|
if (first > -1)
|
||||||
|
address = (void *)(heap_base + first * B_PAGE_SIZE);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (address == NULL)
|
||||||
address = raw_alloc(size, bin_index);
|
address = raw_alloc(size, bin_index);
|
||||||
dprintf("heap: allocated big chunk (%ld bytes), it will never be freed!\n",
|
page = &heap_alloc_table[((unsigned int)address - heap_base) / B_PAGE_SIZE];
|
||||||
size);
|
for (i = 0; i < (size+B_PAGE_SIZE-1)/B_PAGE_SIZE; i++) {
|
||||||
|
page[i].in_use = 1;
|
||||||
|
page[i].cleaning = 0;
|
||||||
|
page[i].bin_index = bin_count;
|
||||||
|
page[i].allocation_id = alloc_id;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bins[bin_index].free_list != NULL) {
|
if (bins[bin_index].free_list != NULL) {
|
||||||
address = bins[bin_index].free_list;
|
address = bins[bin_index].free_list;
|
||||||
@@ -600,6 +639,21 @@ free(void *address)
|
|||||||
// TODO: since the heap must be replaced anyway, we don't
|
// TODO: since the heap must be replaced anyway, we don't
|
||||||
// free this allocation anymore... (tracking them would
|
// free this allocation anymore... (tracking them would
|
||||||
// require some extra stuff)
|
// require some extra stuff)
|
||||||
|
|
||||||
|
for (i = 1; i <= (heap_base_ptr-heap_base)/B_PAGE_SIZE; i++) {
|
||||||
|
if (!page[i].in_use)
|
||||||
|
break;
|
||||||
|
if (page[i].bin_index != bin_count)
|
||||||
|
break;
|
||||||
|
if (page[i].allocation_id != page[0].allocation_id)
|
||||||
|
break;
|
||||||
|
page[i].in_use = 0;
|
||||||
|
page[i].cleaning = 0;
|
||||||
|
page[i].allocation_id = 0;
|
||||||
|
}
|
||||||
|
page[0].in_use = 0;
|
||||||
|
page[0].cleaning = 0;
|
||||||
|
page[0].allocation_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&heap_lock);
|
mutex_unlock(&heap_lock);
|
||||||
@@ -644,11 +698,25 @@ realloc(void *address, size_t newSize)
|
|||||||
|
|
||||||
TRACE(("realloc(): page %p: bin_index %d, free_count %d\n", page, page->bin_index, page->free_count));
|
TRACE(("realloc(): page %p: bin_index %d, free_count %d\n", page, page->bin_index, page->free_count));
|
||||||
|
|
||||||
if (page[0].bin_index >= bin_count)
|
if (page[0].bin_index > bin_count)
|
||||||
panic("realloc(): page %p: invalid bin_index %d\n", page, page->bin_index);
|
panic("realloc(): page %p: invalid bin_index %d\n", page, page->bin_index);
|
||||||
|
|
||||||
|
if (page[0].bin_index < bin_count) {
|
||||||
maxSize = bins[page[0].bin_index].element_size;
|
maxSize = bins[page[0].bin_index].element_size;
|
||||||
minSize = page[0].bin_index > 0 ? bins[page[0].bin_index - 1].element_size : 0;
|
minSize = page[0].bin_index > 0 ? bins[page[0].bin_index - 1].element_size : 0;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
for (i = 1; (addr_t)&page[i] < heap_base; i++) {
|
||||||
|
if (!page[i].in_use)
|
||||||
|
break;
|
||||||
|
if (page[i].bin_index != bin_count)
|
||||||
|
break;
|
||||||
|
if (page[i].allocation_id != page[0].allocation_id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
minSize = 0;
|
||||||
|
maxSize = i * B_PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&heap_lock);
|
mutex_unlock(&heap_lock);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user