Index: kernel/generic/src/adt/bitmap.c
===================================================================
--- kernel/generic/src/adt/bitmap.c	(revision 9d58539899ea3bf36d74e87b391c0a986e338e26)
+++ kernel/generic/src/adt/bitmap.c	(revision f72906c1ceb4b546d431ab8e9c41434425c1096f)
@@ -35,5 +35,6 @@
  *
  * This file implements bitmap ADT and provides functions for
- * setting and clearing ranges of bits.
+ * setting and clearing ranges of bits and for finding ranges
+ * of unset bits.
  */
 
@@ -44,6 +45,43 @@
 #include <macros.h>
 
-#define ALL_ONES 	0xff
-#define ALL_ZEROES	0x00
+#define ALL_ONES    0xff
+#define ALL_ZEROES  0x00
+
+/** Unchecked version of bitmap_get()
+ *
+ * This version of bitmap_get() does not do any boundary checks.
+ *
+ * @param bitmap  Bitmap to access.
+ * @param element Element to access.
+ *
+ * @return Bit value of the element in the bitmap.
+ *
+ */
+static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
+{
+	size_t byte = element / BITMAP_ELEMENT;
+	uint8_t mask = 1 << (element & BITMAP_REMAINER);
+	
+	return !!((bitmap->bits)[byte] & mask);
+}
+
+/** Get bitmap size
+ *
+ * Return the size (in bytes) required for the bitmap.
+ *
+ * @param elements   Number bits stored in bitmap.
+ *
+ * @return Size (in bytes) required for the bitmap.
+ *
+ */
+size_t bitmap_size(size_t elements)
+{
+	size_t size = elements / BITMAP_ELEMENT;
+	
+	if ((elements % BITMAP_ELEMENT) != 0)
+		size++;
+	
+	return size;
+}
 
 /** Initialize bitmap.
@@ -51,41 +89,48 @@
  * No portion of the bitmap is set or cleared by this function.
  *
- * @param bitmap	Bitmap structure.
- * @param map		Address of the memory used to hold the map.
- * @param bits		Number of bits stored in bitmap.
- */
-void bitmap_initialize(bitmap_t *bitmap, uint8_t *map, size_t bits)
-{
-	bitmap->map = map;
-	bitmap->bits = bits;
+ * @param bitmap     Bitmap structure.
+ * @param elements   Number of bits stored in bitmap.
+ * @param data       Address of the memory used to hold the map.
+ *                   The optional 2nd level bitmap follows the 1st
+ *                   level bitmap.
+ *
+ */
+void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
+{
+	bitmap->elements = elements;
+	bitmap->bits = (uint8_t *) data;
+	bitmap->next_fit = 0;
 }
 
 /** Set range of bits.
  *
- * @param bitmap	Bitmap structure.
- * @param start		Starting bit.
- * @param bits		Number of bits to set.
- */
-void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t bits)
-{
-	size_t i = 0;
-	size_t aligned_start;
-	size_t lub;	/* leading unaligned bits */
-	size_t amb;	/* aligned middle bits */
-	size_t tab;	/* trailing aligned bits */
-	
-	ASSERT(start + bits <= bitmap->bits);
-	
-	aligned_start = ALIGN_UP(start, 8);
-	lub = min(aligned_start - start, bits);
-	amb = bits > lub ? bits - lub : 0;
-	tab = amb % 8;
-	
-	if (!bits)
+ * @param bitmap Bitmap structure.
+ * @param start  Starting bit.
+ * @param count  Number of bits to set.
+ *
+ */
+void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t count)
+{
+	ASSERT(start + count <= bitmap->elements);
+	
+	if (count == 0)
 		return;
-
-	if (start + bits < aligned_start) {
+	
+	size_t start_byte = start / BITMAP_ELEMENT;
+	size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
+	
+	/* Leading unaligned bits */
+	size_t lub = min(aligned_start - start, count);
+	
+	/* Aligned middle bits */
+	size_t amb = (count > lub) ? (count - lub) : 0;
+	
+	/* Trailing aligned bits */
+	size_t tab = amb % BITMAP_ELEMENT;
+	
+	if (start + count < aligned_start) {
 		/* Set bits in the middle of byte. */
-		bitmap->map[start / 8] |= ((1 << lub) - 1) << (start & 7);
+		bitmap->bits[start_byte] |=
+		    ((1 << lub) - 1) << (start & BITMAP_REMAINER);
 		return;
 	}
@@ -93,82 +138,199 @@
 	if (lub) {
 		/* Make sure to set any leading unaligned bits. */
-		bitmap->map[start / 8] |= ~((1 << (8 - lub)) - 1);
-	}
-	for (i = 0; i < amb / 8; i++) {
+		bitmap->bits[start_byte] |=
+		    ~((1 << (BITMAP_ELEMENT - lub)) - 1);
+	}
+	
+	size_t i;
+	
+	for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
 		/* The middle bits can be set byte by byte. */
-		bitmap->map[aligned_start / 8 + i] = ALL_ONES;
-	}
+		bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
+		    ALL_ONES;
+	}
+	
 	if (tab) {
 		/* Make sure to set any trailing aligned bits. */
-		bitmap->map[aligned_start / 8 + i] |= (1 << tab) - 1;
-	}
-	
+		bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
+		    (1 << tab) - 1;
+	}
 }
 
 /** Clear range of bits.
  *
- * @param bitmap	Bitmap structure.
- * @param start		Starting bit.
- * @param bits		Number of bits to clear.
- */
-void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t bits)
-{
-	size_t i = 0;
-	size_t aligned_start;
-	size_t lub;	/* leading unaligned bits */
-	size_t amb;	/* aligned middle bits */
-	size_t tab;	/* trailing aligned bits */
-	
-	ASSERT(start + bits <= bitmap->bits);
-	
-	aligned_start = ALIGN_UP(start, 8);
-	lub = min(aligned_start - start, bits);
-	amb = bits > lub ? bits - lub : 0;
-	tab = amb % 8;
-
-	if (!bits)
+ * @param bitmap Bitmap structure.
+ * @param start  Starting bit.
+ * @param count  Number of bits to clear.
+ *
+ */
+void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t count)
+{
+	ASSERT(start + count <= bitmap->elements);
+	
+	if (count == 0)
 		return;
-
-	if (start + bits < aligned_start) {
+	
+	size_t start_byte = start / BITMAP_ELEMENT;
+	size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
+	
+	/* Leading unaligned bits */
+	size_t lub = min(aligned_start - start, count);
+	
+	/* Aligned middle bits */
+	size_t amb = (count > lub) ? (count - lub) : 0;
+	
+	/* Trailing aligned bits */
+	size_t tab = amb % BITMAP_ELEMENT;
+	
+	if (start + count < aligned_start) {
 		/* Set bits in the middle of byte */
-		bitmap->map[start / 8] &= ~(((1 << lub) - 1) << (start & 7));
+		bitmap->bits[start_byte] &=
+		    ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
 		return;
 	}
-
+	
 	if (lub) {
 		/* Make sure to clear any leading unaligned bits. */
-		bitmap->map[start / 8] &= (1 << (8 - lub)) - 1;
-	}
-	for (i = 0; i < amb / 8; i++) {
+		bitmap->bits[start_byte] &=
+		    (1 << (BITMAP_ELEMENT - lub)) - 1;
+	}
+	
+	size_t i;
+	
+	for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
 		/* The middle bits can be cleared byte by byte. */
-		bitmap->map[aligned_start / 8 + i] = ALL_ZEROES;
-	}
+		bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
+		    ALL_ZEROES;
+	}
+	
 	if (tab) {
 		/* Make sure to clear any trailing aligned bits. */
-		bitmap->map[aligned_start / 8 + i] &= ~((1 << tab) - 1);
-	}
-
+		bitmap->bits[aligned_start / BITMAP_ELEMENT + i] &=
+		    ~((1 << tab) - 1);
+	}
+	
+	bitmap->next_fit = start_byte;
 }
 
 /** Copy portion of one bitmap into another bitmap.
  *
- * @param dst		Destination bitmap.
- * @param src		Source bitmap.
- * @param bits		Number of bits to copy.
- */
-void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t bits)
-{
+ * @param dst   Destination bitmap.
+ * @param src   Source bitmap.
+ * @param count Number of bits to copy.
+ *
+ */
+void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t count)
+{
+	ASSERT(count <= dst->elements);
+	ASSERT(count <= src->elements);
+	
 	size_t i;
 	
-	ASSERT(bits <= dst->bits);
-	ASSERT(bits <= src->bits);
-	
-	for (i = 0; i < bits / 8; i++)
-		dst->map[i] = src->map[i];
-	
-	if (bits % 8) {
-		bitmap_clear_range(dst, i * 8, bits % 8);
-		dst->map[i] |= src->map[i] & ((1 << (bits % 8)) - 1);
-	}
+	for (i = 0; i < count / BITMAP_ELEMENT; i++)
+		dst->bits[i] = src->bits[i];
+	
+	if (count % BITMAP_ELEMENT) {
+		bitmap_clear_range(dst, i * BITMAP_ELEMENT,
+		    count % BITMAP_ELEMENT);
+		dst->bits[i] |= src->bits[i] &
+		    ((1 << (count % BITMAP_ELEMENT)) - 1);
+	}
+}
+
+static int constraint_satisfy(size_t index, size_t base, size_t constraint)
+{
+	return (((base + index) & constraint) == 0);
+}
+
+/** Find a continuous zero bit range
+ *
+ * Find a continuous zero bit range in the bitmap. The address
+ * computed as the sum of the index of the first zero bit and
+ * the base argument needs to be compliant with the constraint
+ * (those bits that are set in the constraint cannot be set in
+ * the address).
+ *
+ * If the index argument is non-NULL, the continuous zero range
+ * is set and the index of the first bit is stored to index.
+ * Otherwise the bitmap stays untouched.
+ *
+ * @param bitmap     Bitmap structure.
+ * @param count      Number of continuous zero bits to find.
+ * @param base       Address of the first bit in the bitmap.
+ * @param prefered   Prefered address to start searching from.
+ * @param constraint Constraint for the address of the first zero bit.
+ * @param index      Place to store the index of the first zero
+ *                   bit. Can be NULL (in which case the bitmap
+ *                   is not modified).
+ *
+ * @return Non-zero if a continuous range of zero bits satisfying
+ *         the constraint has been found.
+ * @return Zero otherwise.
+ *
+ */
+int bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
+    size_t prefered, size_t constraint, size_t *index)
+{
+	if (count == 0)
+		return false;
+	
+	size_t size = bitmap_size(bitmap->elements);
+	size_t next_fit = bitmap->next_fit;
+	
+	/*
+	 * Adjust the next-fit value according to the address
+	 * the caller prefers to start the search at.
+	 */
+	if ((prefered > base) && (prefered < base + bitmap->elements)) {
+		size_t prefered_fit = (prefered - base) / BITMAP_ELEMENT;
+		
+		if (prefered_fit > next_fit)
+			next_fit = prefered_fit;
+	}
+	
+	for (size_t pos = 0; pos < size; pos++) {
+		size_t byte = (next_fit + pos) % size;
+		
+		/* Skip if the current byte has all bits set */
+		if (bitmap->bits[byte] == ALL_ONES)
+			continue;
+		
+		size_t byte_bit = byte * BITMAP_ELEMENT;
+		
+		for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
+			size_t i = byte_bit + bit;
+			
+			if (i >= bitmap->elements)
+				break;
+			
+			if (!constraint_satisfy(i, base, constraint))
+				continue;
+			
+			if (!bitmap_get_fast(bitmap, i)) {
+				size_t continuous = 1;
+				
+				for (size_t j = 1; j < count; j++) {
+					if ((i + j < bitmap->elements) &&
+					    (!bitmap_get_fast(bitmap, i + j)))
+						continuous++;
+					else
+						break;
+				}
+				
+				if (continuous == count) {
+					if (index != NULL) {
+						bitmap_set_range(bitmap, i, count);
+						bitmap->next_fit = i / BITMAP_ELEMENT;
+						*index = i;
+					}
+					
+					return true;
+				} else
+					i += continuous;
+			}
+		}
+	}
+	
+	return false;
 }
 
