Redo and improve thread scheduling startup.
[pintos-anon] / src / threads / palloc.c
1 #include "palloc.h"
2 #include <stddef.h>
3 #include <stdint.h>
4 #include "debug.h"
5 #include "init.h"
6 #include "loader.h"
7 #include "lib.h"
8 #include "list.h"
9 #include "mmu.h"
10 #include "synch.h"
11
12 /* Page allocator.  Hands out memory in page-size chunks.
13    See malloc.h for an allocator that hands out smaller
14    chunks. */
15
16 /* A free page owned by the page allocator. */
17 struct page
18   {
19     list_elem free_elem;        /* Free list element. */
20   };
21
22 static struct lock lock;
23 static struct list free_pages;
24 static uint8_t *uninit_start, *uninit_end;
25
26 void
27 palloc_init (void) 
28 {
29   /* Kernel static code and data, in 4 kB pages.
30      
31      We can figure this out because the linker records the start
32      and end of the kernel as _start and _end.  See
33      kernel.lds. */
34   extern char _start, _end;
35   size_t kernel_pages = (&_end - &_start + 4095) / 4096;
36
37   /* Then we know how much is available to allocate. */
38   uninit_start = ptov (LOADER_KERN_BASE + kernel_pages * PGSIZE);
39   uninit_end = ptov (ram_pages * PGSIZE);
40
41   /* Initialize other variables. */
42   lock_init (&lock, "palloc");
43   list_init (&free_pages);
44 }
45
46 void *
47 palloc_get (enum palloc_flags flags)
48 {
49   struct page *page;
50
51   lock_acquire (&lock);
52
53   if (!list_empty (&free_pages))
54     page = list_entry (list_pop_front (&free_pages), struct page, free_elem);
55   else if (uninit_start < uninit_end) 
56     {
57       page = (struct page *) uninit_start;
58       uninit_start += PGSIZE;
59     }
60   else
61     page = NULL;
62
63   if (page != NULL) 
64     {
65       if (flags & PAL_ZERO)
66         memset (page, 0, PGSIZE);
67     }
68   else 
69     {
70       if (flags & PAL_ASSERT)
71         PANIC ("palloc_get: out of pages");
72     }
73
74   lock_release (&lock);
75   
76   return page;
77 }
78
79 void
80 palloc_free (void *page_) 
81 {
82   struct page *page = page_;
83
84   ASSERT (page == pg_round_down (page));
85 #ifndef NDEBUG
86   memset (page, 0xcc, PGSIZE);
87 #endif
88
89   lock_acquire (&lock);
90   list_push_front (&free_pages, &page->free_elem);
91   lock_release (&lock);
92 }