in rts/sm/MBlock.c [223:329]
static void decommitMBlocks(char *addr, uint32_t n)
{
struct free_list *iter, *prev;
W_ size = MBLOCK_SIZE * (W_)n;
W_ address = (W_)addr;
osDecommitMemory(addr, size);
prev = NULL;
for (iter = free_list_head; iter != NULL; iter = iter->next)
{
prev = iter;
if (iter->address + iter->size < address)
continue;
if (iter->address + iter->size == address) {
iter->size += size;
if (address + size == mblock_high_watermark) {
mblock_high_watermark -= iter->size;
if (iter->prev) {
iter->prev->next = NULL;
} else {
ASSERT(iter == free_list_head);
free_list_head = NULL;
}
stgFree(iter);
return;
}
if (iter->next &&
iter->next->address == iter->address + iter->size) {
struct free_list *next;
next = iter->next;
iter->size += next->size;
iter->next = next->next;
if (iter->next) {
iter->next->prev = iter;
/* We don't need to consolidate more */
ASSERT(iter->next->address > iter->address + iter->size);
}
stgFree(next);
}
return;
} else if (address + size == iter->address) {
iter->address = address;
iter->size += size;
/* We don't need to consolidate backwards
(because otherwise it would have been handled by
the previous iteration) */
if (iter->prev) {
ASSERT(iter->prev->address + iter->prev->size < iter->address);
}
return;
} else {
struct free_list *new_iter;
/* All other cases have been handled */
ASSERT(iter->address > address + size);
new_iter = stgMallocBytes(sizeof(struct free_list), "freeMBlocks");
new_iter->address = address;
new_iter->size = size;
new_iter->next = iter;
new_iter->prev = iter->prev;
if (new_iter->prev) {
new_iter->prev->next = new_iter;
} else {
ASSERT(iter == free_list_head);
free_list_head = new_iter;
}
iter->prev = new_iter;
return;
}
}
/* We're past the last free list entry, so we must
be the highest allocation so far
*/
ASSERT(address + size <= mblock_high_watermark);
/* Fast path the case of releasing high or all memory */
if (address + size == mblock_high_watermark) {
mblock_high_watermark -= size;
} else {
struct free_list *new_iter;
new_iter = stgMallocBytes(sizeof(struct free_list), "freeMBlocks");
new_iter->address = address;
new_iter->size = size;
new_iter->next = NULL;
new_iter->prev = prev;
if (new_iter->prev) {
ASSERT(new_iter->prev->next == NULL);
new_iter->prev->next = new_iter;
} else {
ASSERT(free_list_head == NULL);
free_list_head = new_iter;
}
}
}