Index: uspace/lib/c/generic/malloc.c
===================================================================
--- uspace/lib/c/generic/malloc.c	(revision 63f89665fc0283c1661274dc636d5a66e03d48b4)
+++ uspace/lib/c/generic/malloc.c	(revision e1da7ec0aef03e61c7634e6b41960aa3385d4e82)
@@ -43,4 +43,5 @@
 #include <bitops.h>
 #include <mem.h>
+#include <futex.h>
 #include <adt/gcdlcm.h>
 
@@ -75,5 +76,4 @@
 #define NET_SIZE(size)  ((size) - STRUCT_OVERHEAD)
 
-
 /** Header of a heap block
  *
@@ -104,4 +104,7 @@
 extern char _heap;
 
+/** Futex for thread-safe heap manipulation */
+static futex_t malloc_futex = FUTEX_INITIALIZER;
+
 /** Address of heap start */
 static void *heap_start = 0;
@@ -119,4 +122,5 @@
  *
  * Fills in the structures related to a heap block.
+ * Should be called only inside the critical section.
  *
  * @param addr Address of the block.
@@ -144,4 +148,5 @@
  * Verifies that the structures related to a heap block still contain
  * the magic constants. This helps detect heap corruption early on.
+ * Should be called only inside the critical section.
  *
  * @param addr Address of the block.
@@ -161,4 +166,11 @@
 }
 
+/** Increase the heap area size
+ *
+ * Should be called only inside the critical section.
+ *
+ * @param size Number of bytes to grow the heap by.
+ *
+ */
 static bool grow_heap(size_t size)
 {
@@ -189,4 +201,11 @@
 }
 
+/** Decrease the heap area
+ *
+ * Should be called only inside the critical section.
+ *
+ * @param size Number of bytes to shrink the heap by.
+ *
+ */
 static void shrink_heap(void)
 {
@@ -196,5 +215,5 @@
 /** Initialize the heap allocator
  *
- * Finds how much physical memory we have and creates
+ * Find how much physical memory we have and create
  * the heap management structures that mark the whole
  * physical memory as a single free block.
@@ -203,4 +222,6 @@
 void __heap_init(void)
 {
+	futex_down(&malloc_futex);
+	
 	if (as_area_create((void *) &_heap, PAGE_SIZE,
 	    AS_AREA_WRITE | AS_AREA_READ)) {
@@ -213,15 +234,35 @@
 		block_init(heap_start, heap_end - heap_start, true);
 	}
-}
-
+	
+	futex_up(&malloc_futex);
+}
+
+/** Get maximum heap address
+ *
+ */
 uintptr_t get_max_heap_addr(void)
 {
+	futex_down(&malloc_futex);
+	
 	if (max_heap_size == (size_t) -1)
 		max_heap_size =
 		    max((size_t) (heap_end - heap_start), MAX_HEAP_SIZE);
 	
-	return ((uintptr_t) heap_start + max_heap_size);
-}
-
+	uintptr_t max_heap_addr = (uintptr_t) heap_start + max_heap_size;
+	
+	futex_up(&malloc_futex);
+	
+	return max_heap_addr;
+}
+
+/** Split heap block and mark it as used.
+ *
+ * Should be called only inside the critical section.
+ *
+ * @param cur  Heap block to split.
+ * @param size Number of bytes to split and mark from the beginning
+ *             of the block.
+ *
+ */
 static void split_mark(heap_block_head_t *cur, const size_t size)
 {
@@ -243,4 +284,6 @@
 
 /** Allocate a memory block
+ *
+ * Should be called only inside the critical section.
  *
  * @param size  The size of the block to allocate.
@@ -356,4 +399,12 @@
 }
 
+/** Allocate memory by number of elements
+ *
+ * @param nmemb Number of members to allocate.
+ * @param size  Size of one member in bytes.
+ *
+ * @return Allocated memory or NULL.
+ *
+ */
 void *calloc(const size_t nmemb, const size_t size)
 {
@@ -361,14 +412,33 @@
 	if (block == NULL)
 		return NULL;
-
+	
 	memset(block, 0, nmemb * size);
 	return block;
 }
 
+/** Allocate memory
+ *
+ * @param size Number of bytes to allocate.
+ *
+ * @return Allocated memory or NULL.
+ *
+ */
 void *malloc(const size_t size)
 {
-	return malloc_internal(size, BASE_ALIGN);
-}
-
+	futex_down(&malloc_futex);
+	void *block = malloc_internal(size, BASE_ALIGN);
+	futex_up(&malloc_futex);
+	
+	return block;
+}
+
+/** Allocate memory with specified alignment
+ *
+ * @param align Alignment in byes.
+ * @param size  Number of bytes to allocate.
+ *
+ * @return Allocated memory or NULL.
+ *
+ */
 void *memalign(const size_t align, const size_t size)
 {
@@ -379,11 +449,25 @@
 	    1 << (fnzb(max(sizeof(void *), align) - 1) + 1);
 	
-	return malloc_internal(size, palign);
-}
-
+	futex_down(&malloc_futex);
+	void *block = malloc_internal(size, palign);
+	futex_up(&malloc_futex);
+	
+	return block;
+}
+
+/** Reallocate memory block
+ *
+ * @param addr Already allocated memory or NULL.
+ * @param size New size of the memory block.
+ *
+ * @return Reallocated memory or NULL.
+ *
+ */
 void *realloc(const void *addr, const size_t size)
 {
 	if (addr == NULL)
 		return malloc(size);
+	
+	futex_down(&malloc_futex);
 	
 	/* Calculate the position of the header. */
@@ -398,4 +482,5 @@
 	
 	void *ptr = NULL;
+	bool reloc = false;
 	size_t real_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN));
 	size_t orig_size = head->size;
@@ -415,5 +500,7 @@
 	} else {
 		/* Look at the next block. If it is free and the size is
-		   sufficient then merge the two. */
+		   sufficient then merge the two. Otherwise just allocate
+		   a new block, copy the original data into it and
+		   free the original block. */
 		heap_block_head_t *next_head =
 		    (heap_block_head_t *) (((void *) head) + head->size);
@@ -427,10 +514,15 @@
 			
 			ptr = ((void *) head) + sizeof(heap_block_head_t);
-		} else {
-			ptr = malloc(size);
-			if (ptr != NULL) {
-				memcpy(ptr, addr, NET_SIZE(orig_size));
-				free(addr);
-			}
+		} else
+			reloc = true;
+	}
+	
+	futex_up(&malloc_futex);
+	
+	if (reloc) {
+		ptr = malloc(size);
+		if (ptr != NULL) {
+			memcpy(ptr, addr, NET_SIZE(orig_size));
+			free(addr);
 		}
 	}
@@ -442,7 +534,10 @@
  *
  * @param addr The address of the block.
+ *
  */
 void free(const void *addr)
 {
+	futex_down(&malloc_futex);
+	
 	/* Calculate the position of the header. */
 	heap_block_head_t *head
@@ -483,4 +578,6 @@
 	
 	shrink_heap();
+	
+	futex_up(&malloc_futex);
 }
 
