Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision f41485158e45315a8de43576082d32123a88bc6c)
+++ uspace/app/tester/Makefile	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -48,6 +48,8 @@
 	ipc/ping_pong.c \
 	loop/loop1.c \
+	mm/common.c \
 	mm/malloc1.c \
 	mm/malloc2.c \
+	mm/malloc3.c \
 	devs/devman1.c \
 	hw/misc/virtchar1.c \
Index: uspace/app/tester/mm/common.c
===================================================================
--- uspace/app/tester/mm/common.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
+++ uspace/app/tester/mm/common.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * Copyright (c) 2009 Tomas Bures
+ * Copyright (c) 2009 Lubomir Bulej
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <malloc.h>
+#include <as.h>
+#include <adt/list.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "../tester.h"
+#include "common.h"
+
+/*
+ * Global error flag. The flag is set if an error
+ * is encountered (overlapping blocks, inconsistent
+ * block data, etc.)
+ */
+bool error_flag = false;
+
+/*
+ * Memory accounting: the amount of allocated memory and the
+ * number and list of allocated blocks.
+ */
+size_t mem_allocated;
+size_t mem_blocks_count;
+
+static LIST_INITIALIZE(mem_blocks);
+static LIST_INITIALIZE(mem_areas);
+
+/** Initializes the memory accounting structures.
+ *
+ */
+void init_mem(void)
+{
+	mem_allocated = 0;
+	mem_blocks_count = 0;
+}
+
+/** Cleanup all allocated memory blocks and mapped areas.
+ *
+ * Set the global error_flag if an error occurs.
+ *
+ */
+void done_mem(void)
+{
+	link_t *link;
+	
+	while ((link = list_head(&mem_blocks)) != NULL) {
+		mem_block_t *block = list_get_instance(link, mem_block_t, link);
+		free_block(block);
+	}
+	
+	while ((link = list_head(&mem_areas)) != NULL) {
+		mem_area_t *area = list_get_instance(link, mem_area_t, link);
+		unmap_area(area);
+	}
+}
+
+static bool overlap_match(link_t *link, void *addr, size_t size)
+{
+	mem_block_t *block = list_get_instance(link, mem_block_t, link);
+	
+	/* Entry block control structure <mbeg, mend) */
+	uint8_t *mbeg = (uint8_t *) block;
+	uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
+	
+	/* Entry block memory <bbeg, bend) */
+	uint8_t *bbeg = (uint8_t *) block->addr;
+	uint8_t *bend = (uint8_t *) block->addr + block->size;
+	
+	/* Data block <dbeg, dend) */
+	uint8_t *dbeg = (uint8_t *) addr;
+	uint8_t *dend = (uint8_t *) addr + size;
+	
+	/* Check for overlaps */
+	if (((mbeg >= dbeg) && (mbeg < dend)) ||
+	    ((mend > dbeg) && (mend <= dend)) ||
+	    ((bbeg >= dbeg) && (bbeg < dend)) ||
+	    ((bend > dbeg) && (bend <= dend)))
+		return true;
+	
+	return false;
+}
+
+/** Test overlap
+ *
+ * Test whether a block starting at @addr overlaps with another,
+ * previously allocated memory block or its control structure.
+ *
+ * @param addr Initial address of the block
+ * @param size Size of the block
+ *
+ * @return False if the block does not overlap.
+ *
+ */
+static int test_overlap(void *addr, size_t size)
+{
+	bool fnd = false;
+	
+	list_foreach(mem_blocks, link) {
+		if (overlap_match(link, addr, size)) {
+			fnd = true;
+			break;
+		}
+	}
+	
+	return fnd;
+}
+
+/** Checked malloc
+ *
+ * Allocate @size bytes of memory and check whether the chunk comes
+ * from the non-mapped memory region and whether the chunk overlaps
+ * with other, previously allocated, chunks.
+ *
+ * @param size Amount of memory to allocate
+ *
+ * @return NULL if the allocation failed. Sets the global error_flag to
+ *         true if the allocation succeeded but is illegal.
+ *
+ */
+static void *checked_malloc(size_t size)
+{
+	void *data;
+	
+	/* Allocate the chunk of memory */
+	data = malloc(size);
+	if (data == NULL)
+		return NULL;
+	
+	/* Check for overlaps with other chunks */
+	if (test_overlap(data, size)) {
+		TPRINTF("\nError: Allocated block overlaps with another "
+		    "previously allocated block.\n");
+		error_flag = true;
+	}
+	
+	return data;
+}
+
+
+/* Allocate block
+ *
+ * Allocate a block of memory of @size bytes and add record about it into
+ * the mem_blocks list. Return a pointer to the block holder structure or
+ * NULL if the allocation failed.
+ *
+ * If the allocation is illegal (e.g. the memory does not come from the
+ * right region or some of the allocated blocks overlap with others),
+ * set the global error_flag.
+ *
+ * @param size Size of the memory block
+ *
+ */
+mem_block_t *alloc_block(size_t size)
+{
+	/* Check for allocation limit */
+	if (mem_allocated >= MAX_ALLOC)
+		return NULL;
+	
+	/* Allocate the block holder */
+	mem_block_t *block =
+	    (mem_block_t *) checked_malloc(sizeof(mem_block_t));
+	if (block == NULL)
+		return NULL;
+	
+	link_initialize(&block->link);
+	
+	/* Allocate the block memory */
+	block->addr = checked_malloc(size);
+	if (block->addr == NULL) {
+		free(block);
+		return NULL;
+	}
+	
+	block->size = size;
+	
+	/* Register the allocated block */
+	list_append(&block->link, &mem_blocks);
+	mem_allocated += size + sizeof(mem_block_t);
+	mem_blocks_count++;
+	
+	return block;
+}
+
+/** Free block
+ *
+ * Free the block of memory and the block control structure allocated by
+ * alloc_block. Set the global error_flag if an error occurs.
+ *
+ * @param block Block control structure
+ *
+ */
+void free_block(mem_block_t *block)
+{
+	/* Unregister the block */
+	list_remove(&block->link);
+	mem_allocated -= block->size + sizeof(mem_block_t);
+	mem_blocks_count--;
+	
+	/* Free the memory */
+	free(block->addr);
+	free(block);
+}
+
+/** Calculate expected value
+ *
+ * Compute the expected value of a byte located at @pos in memory
+ * block described by @block.
+ *
+ * @param block Memory block control structure
+ * @param pos   Position in the memory block data area
+ *
+ */
+static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
+{
+	return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
+}
+
+/** Fill block
+ *
+ * Fill the memory block controlled by @block with data.
+ *
+ * @param block Memory block control structure
+ *
+ */
+void fill_block(mem_block_t *block)
+{
+	for (uint8_t *pos = block->addr, *end = pos + block->size;
+	    pos < end; pos++)
+		*pos = block_expected_value(block, pos);
+}
+
+/** Check block
+ *
+ * Check whether the block @block contains the data it was filled with.
+ * Set global error_flag if an error occurs.
+ *
+ * @param block Memory block control structure
+ *
+ */
+void check_block(mem_block_t *block)
+{
+	for (uint8_t *pos = block->addr, *end = pos + block->size;
+	    pos < end; pos++) {
+		if (*pos != block_expected_value(block, pos)) {
+			TPRINTF("\nError: Corrupted content of a data block.\n");
+			error_flag = true;
+			return;
+		}
+	}
+}
+
+/** Get random block
+ *
+ * Select a random memory block from the list of allocated blocks.
+ *
+ * @return Block control structure or NULL if the list is empty.
+ *
+ */
+mem_block_t *get_random_block(void)
+{
+	if (mem_blocks_count == 0)
+		return NULL;
+	
+	unsigned int idx = rand() % mem_blocks_count;
+	link_t *entry = list_nth(&mem_blocks, idx);
+	
+	if (entry == NULL) {
+		TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
+		error_flag = true;
+	}
+	
+	return list_get_instance(entry, mem_block_t, link);
+}
+
+/* Map memory area
+ *
+ * Map a memory area of @size bytes and add record about it into
+ * the mem_areas list. Return a pointer to the area holder structure or
+ * NULL if the mapping failed.
+ *
+ * @param size Size of the memory area
+ *
+ */
+mem_area_t *map_area(size_t size)
+{
+	/* Allocate the area holder */
+	mem_area_t *area =
+	    (mem_area_t *) checked_malloc(sizeof(mem_area_t));
+	if (area == NULL)
+		return NULL;
+	
+	link_initialize(&area->link);
+	
+	/* Map the memory area */
+	void *addr = as_get_mappable_page(size);
+	area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
+	if (area->addr == (void *) -1) {
+		free(area);
+		return NULL;
+	}
+	
+	area->size = size;
+	
+	/* Register the allocated area */
+	list_append(&area->link, &mem_areas);
+	
+	return area;
+}
+
+/** Unmap area
+ *
+ * Unmap the memory area and free the block control structure.
+ * Set the global error_flag if an error occurs.
+ *
+ * @param area Memory area control structure
+ *
+ */
+void unmap_area(mem_area_t *area)
+{
+	/* Unregister the area */
+	list_remove(&area->link);
+	
+	/* Free the memory */
+	int ret = as_area_destroy(area->addr);
+	if (ret != EOK)
+		error_flag = true;
+	
+	free(area);
+}
+
+/** Calculate expected value
+ *
+ * Compute the expected value of a byte located at @pos in memory
+ * area described by @area.
+ *
+ * @param area Memory area control structure
+ * @param pos  Position in the memory area data area
+ *
+ */
+static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
+{
+	return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
+}
+
+/** Fill area
+ *
+ * Fill the memory area controlled by @area with data.
+ *
+ * @param area Memory area control structure
+ *
+ */
+void fill_area(mem_area_t *area)
+{
+	for (uint8_t *pos = area->addr, *end = pos + area->size;
+	    pos < end; pos++)
+		*pos = area_expected_value(area, pos);
+}
Index: uspace/app/tester/mm/common.h
===================================================================
--- uspace/app/tester/mm/common.h	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
+++ uspace/app/tester/mm/common.h	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011 Martin Decky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tester
+ * @{
+ */
+/** @file
+ */
+
+#ifndef MM_COMMON_H_
+#define MM_COMMON_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include <adt/list.h>
+
+#define MAX_ALLOC  (16 * 1024 * 1024)
+
+#define AREA_GRANULARITY  16
+#define AREA_SIZE         (4 * PAGE_SIZE)
+
+typedef struct {
+	/* Address of the start of the block */
+	void *addr;
+	
+	/* Size of the memory block */
+	size_t size;
+	
+	/* Link to other blocks */
+	link_t link;
+} mem_block_t;
+
+typedef struct {
+	/* Address of the start of the area */
+	void *addr;
+	
+	/* Size of the memory area */
+	size_t size;
+	/* Link to other areas */
+	link_t link;
+} mem_area_t;
+
+/*
+ * Subphase control structures: subphase termination conditions,
+ * probabilities of individual actions, subphase control structure.
+ */
+
+typedef struct {
+	unsigned int max_cycles;
+	unsigned int no_memory;
+	unsigned int no_allocated;
+} sp_term_cond_t;
+
+typedef struct {
+	unsigned int alloc;
+	unsigned int free;
+} sp_action_prob_t;
+
+typedef struct {
+	const char *name;
+	sp_term_cond_t cond;
+	sp_action_prob_t prob;
+} subphase_t;
+
+/*
+ * Phase control structures: The minimum and maximum block size that
+ * can be allocated during the phase execution, phase control structure.
+ */
+
+typedef struct {
+	size_t min_block_size;
+	size_t max_block_size;
+} ph_alloc_size_t;
+
+typedef struct {
+	const char *name;
+	ph_alloc_size_t alloc;
+	subphase_t *subphases;
+} phase_t;
+
+extern bool error_flag;
+extern size_t mem_allocated;
+extern size_t mem_blocks_count;
+
+#define RETURN_IF_ERROR \
+	do { \
+		if (error_flag) \
+			return; \
+	} while (0)
+
+extern void init_mem(void);
+extern void done_mem(void);
+
+extern mem_block_t *alloc_block(size_t);
+extern void free_block(mem_block_t *);
+extern void fill_block(mem_block_t *);
+extern void check_block(mem_block_t *);
+extern mem_block_t *get_random_block(void);
+
+extern mem_area_t *map_area(size_t);
+extern void fill_area(mem_area_t *);
+extern void unmap_area(mem_area_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/tester/mm/malloc1.c
===================================================================
--- uspace/app/tester/mm/malloc1.c	(revision f41485158e45315a8de43576082d32123a88bc6c)
+++ uspace/app/tester/mm/malloc1.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -30,7 +30,6 @@
 
 #include <stdio.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <malloc.h>
+#include "common.h"
 #include "../tester.h"
 
@@ -45,55 +44,4 @@
  */
 
-/**
- * sizeof_array
- * @array array to determine the size of
- *
- * Returns the size of @array in array elements.
- */
-#define sizeof_array(array) \
-	(sizeof(array) / sizeof((array)[0]))
-
-#define MAX_ALLOC (16 * 1024 * 1024)
-
-/*
- * Subphase control structures: subphase termination conditions,
- * probabilities of individual actions, subphase control structure.
- */
-
-typedef struct {
-	unsigned int max_cycles;
-	unsigned int no_memory;
-	unsigned int no_allocated;
-} sp_term_cond_s;
-
-typedef struct {
-	unsigned int alloc;
-	unsigned int free;
-} sp_action_prob_s;
-
-typedef struct {
-	const char *name;
-	sp_term_cond_s cond;
-	sp_action_prob_s prob;
-} subphase_s;
-
-
-/*
- * Phase control structures: The minimum and maximum block size that
- * can be allocated during the phase execution, phase control structure.
- */
-
-typedef struct {
-	size_t min_block_size;
-	size_t max_block_size;
-} ph_alloc_size_s;
-
-typedef struct {
-	const char *name;
-	ph_alloc_size_s alloc;
-	subphase_s *subphases;
-} phase_s;
-
-
 /*
  * Subphases are defined separately here. This is for two reasons:
@@ -101,5 +49,5 @@
  * how many subphases a phase contains.
  */
-static subphase_s subphases_32B[] = {
+static subphase_t subphases_32B[] = {
 	{
 		.name = "Allocation",
@@ -140,5 +88,5 @@
 };
 
-static subphase_s subphases_128K[] = {
+static subphase_t subphases_128K[] = {
 	{
 		.name = "Allocation",
@@ -179,5 +127,5 @@
 };
 
-static subphase_s subphases_default[] = {
+static subphase_t subphases_default[] = {
 	{
 		.name = "Allocation",
@@ -217,10 +165,9 @@
 	}
 };
-
 
 /*
  * Phase definitions.
  */
-static phase_s phases[] = {
+static phase_t phases[] = {
 	{
 		.name = "32 B memory blocks",
@@ -257,307 +204,10 @@
 };
 
-
-/*
- * Global error flag. The flag is set if an error
- * is encountered (overlapping blocks, inconsistent
- * block data, etc.)
- */
-static bool error_flag = false;
-
-/*
- * Memory accounting: the amount of allocated memory and the
- * number and list of allocated blocks.
- */
-static size_t mem_allocated;
-static size_t mem_blocks_count;
-
-static LIST_INITIALIZE(mem_blocks);
-
-typedef struct {
-	/* Address of the start of the block */
-	void *addr;
-	
-	/* Size of the memory block */
-	size_t size;
-	
-	/* link to other blocks */
-	link_t link;
-} mem_block_s;
-
-typedef mem_block_s *mem_block_t;
-
-
-/** init_mem
- *
- * Initializes the memory accounting structures.
- *
- */
-static void init_mem(void)
+static void do_subphase(phase_t *phase, subphase_t *subphase)
 {
-	mem_allocated = 0;
-	mem_blocks_count = 0;
-}
-
-
-static bool overlap_match(link_t *entry, void *addr, size_t size)
-{
-	mem_block_t mblk = list_get_instance(entry, mem_block_s, link);
-	
-	/* Entry block control structure <mbeg, mend) */
-	uint8_t *mbeg = (uint8_t *) mblk;
-	uint8_t *mend = (uint8_t *) mblk + sizeof(mem_block_s);
-	
-	/* Entry block memory <bbeg, bend) */
-	uint8_t *bbeg = (uint8_t *) mblk->addr;
-	uint8_t *bend = (uint8_t *) mblk->addr + mblk->size;
-	
-	/* Data block <dbeg, dend) */
-	uint8_t *dbeg = (uint8_t *) addr;
-	uint8_t *dend = (uint8_t *) addr + size;
-	
-	/* Check for overlaps */
-	if (((mbeg >= dbeg) && (mbeg < dend)) ||
-		((mend > dbeg) && (mend <= dend)) ||
-		((bbeg >= dbeg) && (bbeg < dend)) ||
-		((bend > dbeg) && (bend <= dend)))
-		return true;
-	
-	return false;
-}
-
-
-/** test_overlap
- *
- * Test whether a block starting at @addr overlaps with another, previously
- * allocated memory block or its control structure.
- *
- * @param addr Initial address of the block
- * @param size Size of the block
- *
- * @return false if the block does not overlap.
- *
- */
-static int test_overlap(void *addr, size_t size)
-{
-	link_t *entry;
-	bool fnd = false;
-	
-	for (entry = mem_blocks.next; entry != &mem_blocks; entry = entry->next) {
-		if (overlap_match(entry, addr, size)) {
-			fnd = true;
-			break;
-		}
-	}
-	
-	return fnd;
-}
-
-
-/** checked_malloc
- *
- * Allocate @size bytes of memory and check whether the chunk comes
- * from the non-mapped memory region and whether the chunk overlaps
- * with other, previously allocated, chunks.
- *
- * @param size Amount of memory to allocate
- *
- * @return NULL if the allocation failed. Sets the global error_flag to
- *         true if the allocation succeeded but is illegal.
- *
- */
-static void *checked_malloc(size_t size)
-{
-	void *data;
-	
-	/* Allocate the chunk of memory */
-	data = malloc(size);
-	if (data == NULL)
-		return NULL;
-	
-	/* Check for overlaps with other chunks */
-	if (test_overlap(data, size)) {
-		TPRINTF("\nError: Allocated block overlaps with another "
-			"previously allocated block.\n");
-		error_flag = true;
-	}
-	
-	return data;
-}
-
-
-/** alloc_block
- *
- * Allocate a block of memory of @size bytes and add record about it into
- * the mem_blocks list. Return a pointer to the block holder structure or
- * NULL if the allocation failed.
- *
- * If the allocation is illegal (e.g. the memory does not come from the
- * right region or some of the allocated blocks overlap with others),
- * set the global error_flag.
- *
- * @param size Size of the memory block
- *
- */
-static mem_block_t alloc_block(size_t size)
-{
-	/* Check for allocation limit */
-	if (mem_allocated >= MAX_ALLOC)
-		return NULL;
-	
-	/* Allocate the block holder */
-	mem_block_t block = (mem_block_t) checked_malloc(sizeof(mem_block_s));
-	if (block == NULL)
-		return NULL;
-	
-	link_initialize(&block->link);
-	
-	/* Allocate the block memory */
-	block->addr = checked_malloc(size);
-	if (block->addr == NULL) {
-		free(block);
-		return NULL;
-	}
-	
-	block->size = size;
-	
-	/* Register the allocated block */
-	list_append(&block->link, &mem_blocks);
-	mem_allocated += size + sizeof(mem_block_s);
-	mem_blocks_count++;
-	
-	return block;
-}
-
-
-/** free_block
- *
- * Free the block of memory and the block control structure allocated by
- * alloc_block. Set the global error_flag if an error occurs.
- *
- * @param block Block control structure
- *
- */
-static void free_block(mem_block_t block)
-{
-	/* Unregister the block */
-	list_remove(&block->link);
-	mem_allocated -= block->size + sizeof(mem_block_s);
-	mem_blocks_count--;
-	
-	/* Free the memory */
-	free(block->addr);
-	free(block);
-}
-
-
-/** expected_value
- *
- * Compute the expected value of a byte located at @pos in memory
- * block described by @blk.
- *
- * @param blk Memory block control structure
- * @param pos Position in the memory block data area
- *
- */
-static inline uint8_t expected_value(mem_block_t blk, uint8_t *pos)
-{
-	return ((unsigned long) blk ^ (unsigned long) pos) & 0xff;
-}
-
-
-/** fill_block
- *
- * Fill the memory block controlled by @blk with data.
- *
- * @param blk Memory block control structure
- *
- */
-static void fill_block(mem_block_t blk)
-{
-	uint8_t *pos;
-	uint8_t *end;
-	
-	for (pos = blk->addr, end = pos + blk->size; pos < end; pos++)
-		*pos = expected_value(blk, pos);
-}
-
-
-/** check_block
- *
- * Check whether the block @blk contains the data it was filled with.
- * Set global error_flag if an error occurs.
- *
- * @param blk Memory block control structure
- *
- */
-static void check_block(mem_block_t blk)
-{
-	uint8_t *pos;
-	uint8_t *end;
-	
-	for (pos = blk->addr, end = pos + blk->size; pos < end; pos++) {
-		if (*pos != expected_value (blk, pos)) {
-			TPRINTF("\nError: Corrupted content of a data block.\n");
-			error_flag = true;
-			return;
-		}
-	}
-}
-
-
-static link_t *list_get_nth(link_t *list, unsigned int i)
-{
-	unsigned int cnt = 0;
-	link_t *entry;
-	
-	for (entry = list->next; entry != list; entry = entry->next) {
-		if (cnt == i)
-			return entry;
-		
-		cnt++;
-	}
-	
-	return NULL;
-}
-
-
-/** get_random_block
- *
- * Select a random memory block from the list of allocated blocks.
- *
- * @return Block control structure or NULL if the list is empty.
- *
- */
-static mem_block_t get_random_block(void)
-{
-	if (mem_blocks_count == 0)
-		return NULL;
-	
-	unsigned int blkidx = rand() % mem_blocks_count;
-	link_t *entry = list_get_nth(&mem_blocks, blkidx);
-	
-	if (entry == NULL) {
-		TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
-		error_flag = true;
-	}
-	
-	return list_get_instance(entry, mem_block_s, link);
-}
-
-
-#define RETURN_IF_ERROR \
-{ \
-	if (error_flag) \
-		return; \
-}
-
-
-static void do_subphase(phase_s *phase, subphase_s *subphase)
-{
-	unsigned int cycles;
-	for (cycles = 0; /* always */; cycles++) {
-		
-		if (subphase->cond.max_cycles &&
-			cycles >= subphase->cond.max_cycles) {
+	for (unsigned int cycles = 0; /* always */; cycles++) {
+		
+		if ((subphase->cond.max_cycles) &&
+		    (cycles >= subphase->cond.max_cycles)) {
 			/*
 			 * We have performed the required number of
@@ -572,9 +222,12 @@
 		unsigned int rnd = rand() % 100;
 		if (rnd < subphase->prob.alloc) {
-			/* Compute a random number lying in interval <min_block_size, max_block_size> */
+			/*
+			 * Compute a random number lying in interval
+			 * <min_block_size, max_block_size>
+			 */
 			int alloc = phase->alloc.min_block_size +
 			    (rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1));
 			
-			mem_block_t blk = alloc_block(alloc);
+			mem_block_t *blk = alloc_block(alloc);
 			RETURN_IF_ERROR;
 			
@@ -585,5 +238,4 @@
 					break;
 				}
-				
 			} else {
 				TPRINTF("A");
@@ -592,5 +244,5 @@
 			
 		} else if (rnd < subphase->prob.free) {
-			mem_block_t blk = get_random_block();
+			mem_block_t *blk = get_random_block();
 			if (blk == NULL) {
 				TPRINTF("F(R)");
@@ -599,5 +251,4 @@
 					break;
 				}
-				
 			} else {
 				TPRINTF("R");
@@ -614,11 +265,8 @@
 }
 
-
-static void do_phase(phase_s *phase)
+static void do_phase(phase_t *phase)
 {
-	unsigned int subno;
-	
-	for (subno = 0; subno < 3; subno++) {
-		subphase_s *subphase = & phase->subphases [subno];
+	for (unsigned int subno = 0; subno < 3; subno++) {
+		subphase_t *subphase = &phase->subphases[subno];
 		
 		TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name);
@@ -632,7 +280,7 @@
 	init_mem();
 	
-	unsigned int phaseno;
-	for (phaseno = 0; phaseno < sizeof_array(phases); phaseno++) {
-		phase_s *phase = &phases[phaseno];
+	for (unsigned int phaseno = 0; phaseno < sizeof_array(phases);
+	    phaseno++) {
+		phase_t *phase = &phases[phaseno];
 		
 		TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name);
@@ -645,4 +293,6 @@
 	}
 	
+	TPRINTF("Cleaning up.\n");
+	done_mem();
 	if (error_flag)
 		return "Test failed";
Index: uspace/app/tester/mm/malloc3.c
===================================================================
--- uspace/app/tester/mm/malloc3.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
+++ uspace/app/tester/mm/malloc3.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * Copyright (c) 2009 Tomas Bures
+ * Copyright (c) 2009 Lubomir Bulej
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "../tester.h"
+
+/*
+ * The test is a slight adaptation of malloc1 test. The major difference
+ * is that the test forces the heap allocator to create multiple
+ * heap areas by creating disturbing address space areas.
+ */
+
+static subphase_t subphases_32B[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 90,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 10,
+			.free = 100
+		}
+	}
+};
+
+static subphase_t subphases_128K[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 70,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 30,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 30,
+			.free = 100
+		}
+	}
+};
+
+static subphase_t subphases_default[] = {
+	{
+		.name = "Allocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 1,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 90,
+			.free = 100
+		}
+	},
+	{
+		.name = "Alloc/Dealloc",
+		.cond = {
+			.max_cycles = 200,
+			.no_memory = 0,
+			.no_allocated = 0,
+		},
+		.prob = {
+			.alloc = 50,
+			.free = 100
+		}
+	},
+	{
+		.name = "Deallocation",
+		.cond = {
+			.max_cycles = 0,
+			.no_memory = 0,
+			.no_allocated = 1,
+		},
+		.prob = {
+			.alloc = 10,
+			.free = 100
+		}
+	}
+};
+
+/*
+ * Phase definitions.
+ */
+static phase_t phases[] = {
+	{
+		.name = "32 B memory blocks",
+		.alloc = {
+			.min_block_size = 32,
+			.max_block_size = 32
+		},
+		.subphases = subphases_32B
+	},
+	{
+		.name = "128 KB memory blocks",
+		.alloc = {
+			.min_block_size = 128 * 1024,
+			.max_block_size = 128 * 1024
+		},
+		.subphases = subphases_128K
+	},
+	{
+		.name = "2500 B memory blocks",
+		.alloc = {
+			.min_block_size = 2500,
+			.max_block_size = 2500
+		},
+		.subphases = subphases_default
+	},
+	{
+		.name = "1 B .. 250000 B memory blocks",
+		.alloc = {
+			.min_block_size = 1,
+			.max_block_size = 250000
+		},
+		.subphases = subphases_default
+	}
+};
+
+static void do_subphase(phase_t *phase, subphase_t *subphase)
+{
+	for (unsigned int cycles = 0; /* always */; cycles++) {
+		
+		if ((subphase->cond.max_cycles) &&
+		    (cycles >= subphase->cond.max_cycles)) {
+			/*
+			 * We have performed the required number of
+			 * cycles. End the current subphase.
+			 */
+			break;
+		}
+		
+		/*
+		 * Decide whether we alloc or free memory in this step.
+		 */
+		unsigned int rnd = rand() % 100;
+		if (rnd < subphase->prob.alloc) {
+			/*
+			 * Compute a random number lying in interval
+			 * <min_block_size, max_block_size>
+			 */
+			int alloc = phase->alloc.min_block_size +
+			    (rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1));
+			
+			mem_block_t *blk = alloc_block(alloc);
+			RETURN_IF_ERROR;
+			
+			if (blk == NULL) {
+				TPRINTF("F(A)");
+				if (subphase->cond.no_memory) {
+					/* We filled the memory. Proceed to next subphase */
+					break;
+				}
+			} else {
+				TPRINTF("A");
+				fill_block(blk);
+				
+				if ((mem_blocks_count % AREA_GRANULARITY) == 0) {
+					mem_area_t *area = map_area(AREA_SIZE);
+					RETURN_IF_ERROR;
+					
+					TPRINTF("*");
+					fill_area(area);
+				}
+			}
+			
+		} else if (rnd < subphase->prob.free) {
+			mem_block_t *blk = get_random_block();
+			if (blk == NULL) {
+				TPRINTF("F(R)");
+				if (subphase->cond.no_allocated) {
+					/* We free all the memory. Proceed to next subphase. */
+					break;
+				}
+			} else {
+				TPRINTF("R");
+				check_block(blk);
+				RETURN_IF_ERROR;
+				
+				free_block(blk);
+				RETURN_IF_ERROR;
+			}
+		}
+	}
+	
+	TPRINTF("\n..  finished.\n");
+}
+
+static void do_phase(phase_t *phase)
+{
+	for (unsigned int subno = 0; subno < 3; subno++) {
+		subphase_t *subphase = &phase->subphases[subno];
+		
+		TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name);
+		do_subphase(phase, subphase);
+		RETURN_IF_ERROR;
+	}
+}
+
+const char *test_malloc3(void)
+{
+	init_mem();
+	
+	for (unsigned int phaseno = 0; phaseno < sizeof_array(phases);
+	    phaseno++) {
+		phase_t *phase = &phases[phaseno];
+		
+		TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name);
+		
+		do_phase(phase);
+		if (error_flag)
+			break;
+		
+		TPRINTF("Phase finished.\n");
+	}
+	
+	TPRINTF("Cleaning up.\n");
+	done_mem();
+	if (error_flag)
+		return "Test failed";
+	
+	return NULL;
+}
Index: uspace/app/tester/mm/malloc3.def
===================================================================
--- uspace/app/tester/mm/malloc3.def	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
+++ uspace/app/tester/mm/malloc3.def	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -0,0 +1,6 @@
+{
+	"malloc3",
+	"Multi-heap memory allocator test",
+	&test_malloc3,
+	true
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision f41485158e45315a8de43576082d32123a88bc6c)
+++ uspace/app/tester/tester.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -63,4 +63,5 @@
 #include "mm/malloc1.def"
 #include "mm/malloc2.def"
+#include "mm/malloc3.def"
 #include "hw/serial/serial1.def"
 #include "hw/misc/virtchar1.def"
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision f41485158e45315a8de43576082d32123a88bc6c)
+++ uspace/app/tester/tester.h	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -46,10 +46,19 @@
 extern char **test_argv;
 
+/**
+ * sizeof_array
+ * @array array to determine the size of
+ *
+ * Returns the size of @array in array elements.
+ */
+#define sizeof_array(array) \
+	(sizeof(array) / sizeof((array)[0]))
+
 #define TPRINTF(format, ...) \
-	{ \
+	do { \
 		if (!test_quiet) { \
-			fprintf(stderr, format, ##__VA_ARGS__); \
+			fprintf(stderr, (format), ##__VA_ARGS__); \
 		} \
-	}
+	} while (0)
 
 typedef const char *(*test_entry_t)(void);
@@ -79,4 +88,5 @@
 extern const char *test_malloc1(void);
 extern const char *test_malloc2(void);
+extern const char *test_malloc3(void);
 extern const char *test_serial1(void);
 extern const char *test_virtchar1(void);
Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision f41485158e45315a8de43576082d32123a88bc6c)
+++ uspace/lib/c/generic/malloc.c	(revision 013a5d79953470b10d851495a8b1a4246a71a5a4)
@@ -65,4 +65,14 @@
 #define BASE_ALIGN  16
 
+/** Heap shrink granularity
+ *
+ * Try not to pump and stress the heap to much
+ * by shrinking and enlarging it too often.
+ * A heap area won't shrunk if it the released
+ * free block is smaller than this constant.
+ *
+ */
+#define SHRINK_GRANULARITY  (64 * PAGE_SIZE)
+
 /** Overhead of each heap block. */
 #define STRUCT_OVERHEAD \
@@ -86,6 +96,19 @@
  *
  */
-#define AREA_FIRST_BLOCK(area) \
+#define AREA_FIRST_BLOCK_HEAD(area) \
 	(ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN))
+
+/** Get last block in heap area.
+ *
+ */
+#define AREA_LAST_BLOCK_FOOT(area) \
+	(((uintptr_t) (area)->end) - sizeof(heap_block_foot_t))
+
+/** Get header in heap block.
+ *
+ */
+#define BLOCK_HEAD(foot) \
+	((heap_block_head_t *) \
+	    (((uintptr_t) (foot)) + sizeof(heap_block_foot_t) - (foot)->size))
 
 /** Get footer in heap block.
@@ -94,5 +117,5 @@
 #define BLOCK_FOOT(head) \
 	((heap_block_foot_t *) \
-	    (((uintptr_t) head) + head->size - sizeof(heap_block_foot_t)))
+	    (((uintptr_t) (head)) + (head)->size - sizeof(heap_block_foot_t)))
 
 /** Heap area.
@@ -115,4 +138,7 @@
 	void *end;
 	
+	/** Previous heap area */
+	struct heap_area *prev;
+	
 	/** Next heap area */
 	struct heap_area *next;
@@ -212,4 +238,6 @@
 /** Check a heap area structure
  *
+ * Should be called only inside the critical section.
+ *
  * @param addr Address of the heap area.
  *
@@ -220,4 +248,5 @@
 	
 	assert(area->magic == HEAP_AREA_MAGIC);
+	assert(addr == area->start);
 	assert(area->start < area->end);
 	assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
@@ -227,6 +256,7 @@
 /** Create new heap area
  *
- * @param start Preffered starting address of the new area.
- * @param size  Size of the area.
+ * Should be called only inside the critical section.
+ *
+ * @param size Size of the area.
  *
  */
@@ -248,10 +278,10 @@
 	
 	area->start = astart;
-	area->end = (void *)
-	    ALIGN_DOWN((uintptr_t) astart + asize, BASE_ALIGN);
+	area->end = (void *) ((uintptr_t) astart + asize);
+	area->prev = NULL;
 	area->next = NULL;
 	area->magic = HEAP_AREA_MAGIC;
 	
-	void *block = (void *) AREA_FIRST_BLOCK(area);
+	void *block = (void *) AREA_FIRST_BLOCK_HEAD(area);
 	size_t bsize = (size_t) (area->end - block);
 	
@@ -262,4 +292,5 @@
 		last_heap_area = area;
 	} else {
+		area->prev = last_heap_area;
 		last_heap_area->next = area;
 		last_heap_area = area;
@@ -271,6 +302,10 @@
 /** Try to enlarge a heap area
  *
+ * Should be called only inside the critical section.
+ *
  * @param area Heap area to grow.
- * @param size Gross size of item to allocate (bytes).
+ * @param size Gross size to grow (bytes).
+ *
+ * @return True if successful.
  *
  */
@@ -282,10 +317,8 @@
 	area_check(area);
 	
-	size_t asize = ALIGN_UP((size_t) (area->end - area->start) + size,
-	    PAGE_SIZE);
-	
 	/* New heap area size */
-	void *end = (void *)
-	    ALIGN_DOWN((uintptr_t) area->start + asize, BASE_ALIGN);
+	size_t gross_size = (size_t) (area->end - area->start) + size;
+	size_t asize = ALIGN_UP(gross_size, PAGE_SIZE);
+	void *end = (void *) ((uintptr_t) area->start + asize);
 	
 	/* Check for overflow */
@@ -299,5 +332,7 @@
 	
 	/* Add new free block */
-	block_init(area->end, (size_t) (end - area->end), true, area);
+	size_t net_size = (size_t) (end - area->end);
+	if (net_size > 0)
+		block_init(area->end, net_size, true, area);
 	
 	/* Update heap area parameters */
@@ -309,4 +344,6 @@
 /** Try to enlarge any of the heap areas
  *
+ * Should be called only inside the critical section.
+ *
  * @param size Gross size of item to allocate (bytes).
  *
@@ -318,6 +355,6 @@
 	
 	/* First try to enlarge some existing area */
-	heap_area_t *area;
-	for (area = first_heap_area; area != NULL; area = area->next) {
+	for (heap_area_t *area = first_heap_area; area != NULL;
+	    area = area->next) {
 		if (area_grow(area, size))
 			return true;
@@ -325,14 +362,113 @@
 	
 	/* Eventually try to create a new area */
-	return area_create(AREA_FIRST_BLOCK(size));
-}
-
-/** Try to shrink heap space
- *
+	return area_create(AREA_FIRST_BLOCK_HEAD(size));
+}
+
+/** Try to shrink heap
+ *
+ * Should be called only inside the critical section.
  * In all cases the next pointer is reset.
  *
- */
-static void heap_shrink(void)
-{
+ * @param area Last modified heap area.
+ *
+ */
+static void heap_shrink(heap_area_t *area)
+{
+	area_check(area);
+	
+	heap_block_foot_t *last_foot =
+	    (heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area);
+	heap_block_head_t *last_head = BLOCK_HEAD(last_foot);
+	
+	block_check((void *) last_head);
+	assert(last_head->area == area);
+	
+	if (last_head->free) {
+		/*
+		 * The last block of the heap area is
+		 * unused. The area might be potentially
+		 * shrunk.
+		 */
+		
+		heap_block_head_t *first_head =
+		    (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(area);
+		
+		block_check((void *) first_head);
+		assert(first_head->area == area);
+		
+		if (first_head == last_head) {
+			/*
+			 * The entire heap area consists of a single
+			 * free heap block. This means we can get rid
+			 * of it entirely.
+			 */
+			
+			heap_area_t *prev = area->prev;
+			heap_area_t *next = area->next;
+			
+			if (prev != NULL) {
+				area_check(prev);
+				prev->next = next;
+			} else
+				first_heap_area = next;
+			
+			if (next != NULL) {
+				area_check(next);
+				next->prev = prev;
+			} else
+				last_heap_area = prev;
+			
+			as_area_destroy(area->start);
+		} else if (last_head->size >= SHRINK_GRANULARITY) {
+			/*
+			 * Make sure that we always shrink the area
+			 * by a multiple of page size and update
+			 * the block layout accordingly.
+			 */
+			
+			size_t shrink_size = ALIGN_DOWN(last_head->size, PAGE_SIZE);
+			size_t asize = (size_t) (area->end - area->start) - shrink_size;
+			void *end = (void *) ((uintptr_t) area->start + asize);
+			
+			/* Resize the address space area */
+			int ret = as_area_resize(area->start, asize, 0);
+			if (ret != EOK)
+				abort();
+			
+			/* Update heap area parameters */
+			area->end = end;
+			
+			/* Update block layout */
+			void *last = (void *) last_head;
+			size_t excess = (size_t) (area->end - last);
+			
+			if (excess > 0) {
+				if (excess >= STRUCT_OVERHEAD) {
+					/*
+					 * The previous block cannot be free and there
+					 * is enough free space left in the area to
+					 * create a new free block.
+					 */
+					block_init(last, excess, true, area);
+				} else {
+					/*
+					 * The excess is small. Therefore just enlarge
+					 * the previous block.
+					 */
+					heap_block_foot_t *prev_foot = (heap_block_foot_t *)
+					    (((uintptr_t) last_head) - sizeof(heap_block_foot_t));
+					heap_block_head_t *prev_head = BLOCK_HEAD(prev_foot);
+					
+					block_check((void *) prev_head);
+					
+					block_init(prev_head, prev_head->size + excess,
+					    prev_head->free, area);
+				}
+			}
+			
+			
+		}
+	}
+	
 	next = NULL;
 }
@@ -398,9 +534,8 @@
 {
 	area_check((void *) area);
-	assert((void *) first_block >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) first_block >= (void *) AREA_FIRST_BLOCK_HEAD(area));
 	assert((void *) first_block < area->end);
 	
-	heap_block_head_t *cur;
-	for (cur = first_block; (void *) cur < area->end;
+	for (heap_block_head_t *cur = first_block; (void *) cur < area->end;
 	    cur = (heap_block_head_t *) (((void *) cur) + cur->size)) {
 		block_check(cur);
@@ -436,5 +571,5 @@
 					 * data in (including alignment).
 					 */
-					if ((void *) cur > (void *) AREA_FIRST_BLOCK(area)) {
+					if ((void *) cur > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
 						/*
 						 * There is a block before the current block.
@@ -496,8 +631,8 @@
 							size_t reduced_size = cur->size - excess;
 							cur = (heap_block_head_t *)
-							    (AREA_FIRST_BLOCK(area) + excess);
+							    (AREA_FIRST_BLOCK_HEAD(area) + excess);
 							
-							block_init((void *) AREA_FIRST_BLOCK(area), excess,
-							    true, area);
+							block_init((void *) AREA_FIRST_BLOCK_HEAD(area),
+							    excess, true, area);
 							block_init(cur, reduced_size, true, area);
 							split_mark(cur, real_size);
@@ -552,8 +687,8 @@
 	
 	/* Search the entire heap */
-	heap_area_t *area;
-	for (area = first_heap_area; area != NULL; area = area->next) {
+	for (heap_area_t *area = first_heap_area; area != NULL;
+	    area = area->next) {
 		heap_block_head_t *first = (heap_block_head_t *)
-		    AREA_FIRST_BLOCK(area);
+		    AREA_FIRST_BLOCK_HEAD(area);
 		
 		void *addr = malloc_area(area, first, split, real_size,
@@ -657,5 +792,5 @@
 	
 	area_check(area);
-	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
 	assert((void *) head < area->end);
 	
@@ -675,5 +810,5 @@
 			block_init((void *) head + real_size,
 			    orig_size - real_size, true, area);
-			heap_shrink();
+			heap_shrink(area);
 		}
 		
@@ -734,5 +869,5 @@
 	
 	area_check(area);
-	assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
+	assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
 	assert((void *) head < area->end);
 	
@@ -751,5 +886,5 @@
 	
 	/* Look at the previous block. If it is free, merge the two. */
-	if ((void *) head > (void *) AREA_FIRST_BLOCK(area)) {
+	if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
 		heap_block_foot_t *prev_foot =
 		    (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t));
@@ -765,5 +900,5 @@
 	}
 	
-	heap_shrink();
+	heap_shrink(area);
 	
 	futex_up(&malloc_futex);
