9910bf433c7b1f2eac0a518de062a9a00ed7cafc
[pintos-anon] / src / threads / malloc.c
1 #include "threads/malloc.h"
2 #include <debug.h>
3 #include <list.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include "threads/mmu.h"
8 #include "threads/palloc.h"
9 #include "threads/synch.h"
10
11 /* A simple implementation of malloc().
12
13    The size of each request, in bytes, is rounded up to a power
14    of 2 and assigned to the "descriptor" that manages blocks of
15    that size.  The descriptor keeps a list of free blocks.  If
16    the free list is nonempty, one of its blocks is used to
17    satisfy the request.
18
19    Otherwise, a new page of memory, called an "arena", is
20    obtained from the page allocator (if none is available,
21    malloc() returns a null pointer).  The new arena is divided
22    into blocks, all of which are added to the descriptor's free
23    list.  Then we return one of the new blocks.
24
25    When we free a block, we add it to its descriptor's free list.
26    But if the arena that the block was in now has no in-use
27    blocks, we remove all of the arena's blocks from the free list
28    and give the arena back to the page allocator.
29
30    Major limitation: the largest block that can be allocated is
31    PGSIZE / 2, or 2 kB.  Use palloc_get() to allocate pages (4 kB
32    blocks).  You're on your own if you need more memory than
33    that. */
34
35 /* Descriptor. */
36 struct desc
37   {
38     size_t block_size;          /* Size of each element in bytes. */
39     size_t blocks_per_arena;    /* Number of blocks in an arena. */
40     struct list free_list;      /* List of free blocks. */
41     struct lock lock;           /* Lock. */
42   };
43
44 /* Magic number for detecting arena corruption. */
45 #define ARENA_MAGIC 0x9a548eed
46
47 /* Arena. */
48 struct arena 
49   {
50     unsigned magic;             /* Always set to ARENA_MAGIC. */
51     struct desc *desc;          /* Owning descriptor. */
52     size_t free_cnt;            /* Number of free blocks. */
53   };
54
55 /* Free block. */
56 struct block 
57   {
58     list_elem free_elem;        /* Free list element. */
59   };
60
61 /* Our set of descriptors. */
62 static struct desc descs[10];   /* Descriptors. */
63 static size_t desc_cnt;         /* Number of descriptors. */
64
65 static struct arena *block_to_arena (struct block *);
66 static struct block *arena_to_block (struct arena *, size_t idx);
67
68 /* Initializes the malloc() descriptors. */
69 void
70 malloc_init (void) 
71 {
72   size_t block_size;
73
74   for (block_size = 16; block_size < PGSIZE; block_size *= 2)
75     {
76       struct desc *d = &descs[desc_cnt++];
77       ASSERT (desc_cnt <= sizeof descs / sizeof *descs);
78       d->block_size = block_size;
79       d->blocks_per_arena = (PGSIZE - sizeof (struct arena)) / block_size;
80       list_init (&d->free_list);
81       lock_init (&d->lock, "malloc");
82     }
83 }
84
85 /* Obtains and returns a new block of at least SIZE bytes.
86    Returns a null pointer if memory is not available. */
87 void *
88 malloc (size_t size) 
89 {
90   struct desc *d;
91   struct block *b;
92   struct arena *a;
93
94   /* A null pointer satisfies a request for 0 bytes. */
95   if (size == 0)
96     return NULL;
97
98   /* Find the smallest descriptor that satisfies a SIZE-byte
99      request. */
100   for (d = descs; d < descs + desc_cnt; d++)
101     if (d->block_size >= size)
102       break;
103   if (d == descs + desc_cnt) 
104     {
105       printf ("malloc: %zu byte allocation too big\n", size);
106       return NULL; 
107     }
108
109   lock_acquire (&d->lock);
110
111   /* If the free list is empty, create a new arena. */
112   if (list_empty (&d->free_list))
113     {
114       size_t i;
115
116       /* Allocate a page. */
117       a = palloc_get (0);
118       if (a == NULL) 
119         {
120           lock_release (&d->lock);
121           return NULL; 
122         }
123
124       /* Initialize arena and add its blocks to the free list. */
125       a->magic = ARENA_MAGIC;
126       a->desc = d;
127       a->free_cnt = d->blocks_per_arena;
128       for (i = 0; i < d->blocks_per_arena; i++) 
129         {
130           struct block *b = arena_to_block (a, i);
131           list_push_back (&d->free_list, &b->free_elem);
132         }
133     }
134
135   /* Get a block from free list and return it. */
136   b = list_entry (list_pop_front (&d->free_list), struct block, free_elem);
137   a = block_to_arena (b);
138   a->free_cnt--;
139   lock_release (&d->lock);
140   return b;
141 }
142
143 /* Allocates and return A times B bytes initialized to zeroes.
144    Returns a null pointer if memory is not available. */
145 void *
146 calloc (size_t a, size_t b) 
147 {
148   void *p;
149   size_t size;
150
151   /* Calculate block size. */
152   size = a * b;
153   if (size < a || size < b)
154     return NULL;
155
156   /* Allocate and zero memory. */
157   p = malloc (size);
158   if (p != NULL)
159     memset (p, 0, size);
160
161   return p;
162 }
163
164 /* Frees block P, which must have been previously allocated with
165    malloc() or calloc(). */
166 void
167 free (void *p) 
168 {
169   struct block *b;
170   struct arena *a;
171   struct desc *d;
172
173   if (p == NULL)
174     return;
175
176   b = p;
177   a = block_to_arena (b);
178   d = a->desc;
179
180 #ifndef NDEBUG
181   memset (b, 0xcd, d->block_size);
182 #endif
183   
184   lock_acquire (&d->lock);
185
186
187   /* Add block to free list. */
188   list_push_front (&d->free_list, &b->free_elem);
189
190   /* If the arena is now entirely unused, free it. */
191   if (++a->free_cnt >= d->blocks_per_arena) 
192     {
193       size_t i;
194
195       ASSERT (a->free_cnt == d->blocks_per_arena);
196       for (i = 0; i < d->blocks_per_arena; i++) 
197         {
198           struct block *b = arena_to_block (a, i);
199           list_remove (&b->free_elem);
200         }
201       palloc_free (a);
202     }
203
204   lock_release (&d->lock);
205 }
206 \f
207 /* Returns the arena that block B is inside. */
208 static struct arena *
209 block_to_arena (struct block *b)
210 {
211   struct arena *a = pg_round_down (b);
212   ASSERT (a != NULL);
213   ASSERT (a->magic == ARENA_MAGIC);
214   return a;
215 }
216
217 /* Returns the (IDX - 1)'th block within arena A. */
218 static struct block *
219 arena_to_block (struct arena *a, size_t idx) 
220 {
221   ASSERT (a != NULL);
222   ASSERT (a->magic == ARENA_MAGIC);
223   ASSERT (idx < a->desc->blocks_per_arena);
224   return (struct block *) ((uint8_t *) a
225                            + sizeof *a
226                            + idx * a->desc->block_size);
227 }