Index: kernel/generic/src/mm/frame.c
===================================================================
--- kernel/generic/src/mm/frame.c	(revision 08a19ba655441635df46ca12a53414694005e074)
+++ kernel/generic/src/mm/frame.c	(revision 1a1744ec1103a45c20bd4031d645eaf84be2bb5f)
@@ -59,4 +59,6 @@
 #include <adt/list.h>
 #include <synch/spinlock.h>
+#include <synch/mutex.h>
+#include <synch/condvar.h>
 #include <arch/asm.h>
 #include <arch.h>
@@ -104,4 +106,11 @@
 static zones_t zones;
 
+/*
+ * Synchronization primitives used to sleep when there is no memory
+ * available.
+ */
+mutex_t zones_mtx;
+condvar_t zones_cv;
+int new_freed_mem = false;
 
 /********************/
@@ -992,12 +1001,26 @@
 	if (!zone) {
 		/*
-		 * TODO: Sleep until frames are available again.
+		 * Sleep until some frames are available again.
 		 */
+		if (flags & FRAME_ATOMIC) {
+			interrupts_restore(ipl);
+			return 0;
+		}
+		
+#ifdef CONFIG_DEBUG
+		printf("Thread %" PRIu64 " falling asleep, low memory.\n", THREAD->tid);
+#endif
+
+		mutex_lock(&zones_mtx);
+		if (!new_freed_mem)
+			condvar_wait(&zones_cv, &zones_mtx);
+		new_freed_mem = false;
+		mutex_unlock(&zones_mtx);
+
+#ifdef CONFIG_DEBUG
+		printf("Thread %" PRIu64 " woken up, memory available.\n", THREAD->tid);
+#endif
+
 		interrupts_restore(ipl);
-
-		if (flags & FRAME_ATOMIC)
-			return 0;
-		
-		panic("Sleep not implemented.\n");
 		goto loop;
 	}
@@ -1029,14 +1052,23 @@
 
 	ipl = interrupts_disable();
-	
+
 	/*
 	 * First, find host frame zone for addr.
 	 */
-	zone = find_zone_and_lock(pfn,NULL);
+	zone = find_zone_and_lock(pfn, NULL);
 	ASSERT(zone);
 	
-	zone_frame_free(zone, pfn-zone->base);
+	zone_frame_free(zone, pfn - zone->base);
 	
 	spinlock_unlock(&zone->lock);
+	
+	/*
+	 * Signal that some memory has been freed.
+	 */
+	mutex_lock(&zones_mtx);	
+	new_freed_mem = true;
+	condvar_broadcast(&zones_cv);
+	mutex_unlock(&zones_mtx);
+
 	interrupts_restore(ipl);
 }
@@ -1117,4 +1149,7 @@
 		frame_mark_unavailable(0, 1);
 	}
+
+	mutex_initialize(&zones_mtx, MUTEX_ACTIVE);	/* mimic spinlock */
+	condvar_initialize(&zones_cv);
 }
 
