Redo and improve thread scheduling startup.
[pintos-anon] / src / threads / palloc.c
index 62e24cada4756dfa5917f74fac03512ce7626ad4..0b771fdb21f6451c008a61a5012124d2e0be9e10 100644 (file)
@@ -5,15 +5,22 @@
 #include "init.h"
 #include "loader.h"
 #include "lib.h"
+#include "list.h"
 #include "mmu.h"
+#include "synch.h"
+
+/* Page allocator.  Hands out memory in page-size chunks.
+   See malloc.h for an allocator that hands out smaller
+   chunks. */
 
 /* A free page owned by the page allocator. */
 struct page
   {
-    struct page *next;  /* Next free page, or null at end of chain. */
+    list_elem free_elem;        /* Free list element. */
   };
 
-static struct page *free_pages;
+static struct lock lock;
+static struct list free_pages;
 static uint8_t *uninit_start, *uninit_end;
 
 void
@@ -25,12 +32,15 @@ palloc_init (void)
      and end of the kernel as _start and _end.  See
      kernel.lds. */
   extern char _start, _end;
-  size_t kernel_pages;  
-  kernel_pages = (&_end - &_start + 4095) / 4096;
+  size_t kernel_pages = (&_end - &_start + 4095) / 4096;
 
   /* Then we know how much is available to allocate. */
   uninit_start = ptov (LOADER_KERN_BASE + kernel_pages * PGSIZE);
   uninit_end = ptov (ram_pages * PGSIZE);
+
+  /* Initialize other variables. */
+  lock_init (&lock, "palloc");
+  list_init (&free_pages);
 }
 
 void *
@@ -38,16 +48,20 @@ palloc_get (enum palloc_flags flags)
 {
   struct page *page;
 
-  if (free_pages == NULL && uninit_start < uninit_end) 
+  lock_acquire (&lock);
+
+  if (!list_empty (&free_pages))
+    page = list_entry (list_pop_front (&free_pages), struct page, free_elem);
+  else if (uninit_start < uninit_end) 
     {
-      palloc_free (uninit_start);
+      page = (struct page *) uninit_start;
       uninit_start += PGSIZE;
     }
+  else
+    page = NULL;
 
-  page = free_pages;
   if (page != NULL) 
     {
-      free_pages = page->next;
       if (flags & PAL_ZERO)
         memset (page, 0, PGSIZE);
     }
@@ -56,6 +70,8 @@ palloc_get (enum palloc_flags flags)
       if (flags & PAL_ASSERT)
         PANIC ("palloc_get: out of pages");
     }
+
+  lock_release (&lock);
   
   return page;
 }
@@ -64,10 +80,13 @@ void
 palloc_free (void *page_) 
 {
   struct page *page = page_;
-  ASSERT((uintptr_t) page % PGSIZE == 0);
+
+  ASSERT (page == pg_round_down (page));
 #ifndef NDEBUG
   memset (page, 0xcc, PGSIZE);
 #endif
-  page->next = free_pages;
-  free_pages = page;
+
+  lock_acquire (&lock);
+  list_push_front (&free_pages, &page->free_elem);
+  lock_release (&lock);
 }