00001 #include "threads/malloc.h"
00002
00003 #include <debug.h>
00004 #include <list.h>
00005 #include <round.h>
00006 #include <stdint.h>
00007 #include <stdio.h>
00008 #include <string.h>
00009 #include "threads/palloc.h"
00010 #include "threads/synch.h"
00011 #include "threads/vaddr.h"
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 struct desc
00040 {
00041 size_t block_size;
00042 size_t blocks_per_arena;
00043 struct list free_list;
00044 struct lock lock;
00045 };
00046
00047
00048 #define ARENA_MAGIC 0x9a548eed
00049
00050
00051 struct arena
00052 {
00053 unsigned magic;
00054 struct desc *desc;
00055 size_t free_cnt;
00056 };
00057
00058
00059 struct block
00060 {
00061 struct list_elem free_elem;
00062 };
00063
00064
00065 static struct desc descs[10];
00066 static size_t desc_cnt;
00067
00068 static struct arena *block_to_arena (struct block *);
00069 static struct block *arena_to_block (struct arena *, size_t idx);
00070
00071
00072 void
00073 malloc_init (void)
00074 {
00075 size_t block_size;
00076
00077 for (block_size = 16; block_size < PGSIZE / 2; block_size *= 2)
00078 {
00079 struct desc *d = &descs[desc_cnt++];
00080 ASSERT (desc_cnt <= sizeof descs / sizeof *descs);
00081 d->block_size = block_size;
00082 d->blocks_per_arena = (PGSIZE - sizeof (struct arena)) / block_size;
00083 list_init (&d->free_list);
00084 lock_init (&d->lock);
00085 }
00086 }
00087
00088
00089
00090 void *
00091 malloc (size_t size)
00092 {
00093 struct desc *d;
00094 struct block *b;
00095 struct arena *a;
00096
00097
00098 if (size == 0)
00099 return NULL;
00100
00101
00102
00103 for (d = descs; d < descs + desc_cnt; d++)
00104 if (d->block_size >= size)
00105 break;
00106 if (d == descs + desc_cnt)
00107 {
00108
00109
00110 size_t page_cnt = DIV_ROUND_UP (size + sizeof *a, PGSIZE);
00111 a = palloc_get_multiple (0, page_cnt);
00112 if (a == NULL)
00113 return NULL;
00114
00115
00116
00117 a->magic = ARENA_MAGIC;
00118 a->desc = NULL;
00119 a->free_cnt = page_cnt;
00120 return a + 1;
00121 }
00122
00123 lock_acquire (&d->lock);
00124
00125
00126 if (list_empty (&d->free_list))
00127 {
00128 size_t i;
00129
00130
00131 a = palloc_get_page (0);
00132 if (a == NULL)
00133 {
00134 lock_release (&d->lock);
00135 return NULL;
00136 }
00137
00138
00139 a->magic = ARENA_MAGIC;
00140 a->desc = d;
00141 a->free_cnt = d->blocks_per_arena;
00142 for (i = 0; i < d->blocks_per_arena; i++)
00143 {
00144 struct block *b = arena_to_block (a, i);
00145 list_push_back (&d->free_list, &b->free_elem);
00146 }
00147 }
00148
00149
00150 b = list_entry (list_pop_front (&d->free_list), struct block, free_elem);
00151 a = block_to_arena (b);
00152 a->free_cnt--;
00153 lock_release (&d->lock);
00154 return b;
00155 }
00156
00157
00158
00159 void *
00160 calloc (size_t a, size_t b)
00161 {
00162 void *p;
00163 size_t size;
00164
00165
00166 size = a * b;
00167 if (size < a || size < b)
00168 return NULL;
00169
00170
00171 p = malloc (size);
00172 if (p != NULL)
00173 memset (p, 0, size);
00174
00175 return p;
00176 }
00177
00178
00179 static size_t
00180 block_size (void *block)
00181 {
00182 struct block *b = block;
00183 struct arena *a = block_to_arena (b);
00184 struct desc *d = a->desc;
00185
00186 return d != NULL ? d->block_size : PGSIZE * a->free_cnt - pg_ofs (block);
00187 }
00188
00189
00190
00191
00192
00193
00194
00195 void *
00196 realloc (void *old_block, size_t new_size)
00197 {
00198 if (new_size == 0)
00199 {
00200 free (old_block);
00201 return NULL;
00202 }
00203 else
00204 {
00205 void *new_block = malloc (new_size);
00206 if (old_block != NULL && new_block != NULL)
00207 {
00208 size_t old_size = block_size (old_block);
00209 size_t min_size = new_size < old_size ? new_size : old_size;
00210 memcpy (new_block, old_block, min_size);
00211 free (old_block);
00212 }
00213 return new_block;
00214 }
00215 }
00216
00217
00218
00219 void
00220 free (void *p)
00221 {
00222 if (p != NULL)
00223 {
00224 struct block *b = p;
00225 struct arena *a = block_to_arena (b);
00226 struct desc *d = a->desc;
00227
00228 if (d != NULL)
00229 {
00230
00231
00232 #ifndef NDEBUG
00233
00234 memset (b, 0xcc, d->block_size);
00235 #endif
00236
00237 lock_acquire (&d->lock);
00238
00239
00240 list_push_front (&d->free_list, &b->free_elem);
00241
00242
00243 if (++a->free_cnt >= d->blocks_per_arena)
00244 {
00245 size_t i;
00246
00247 ASSERT (a->free_cnt == d->blocks_per_arena);
00248 for (i = 0; i < d->blocks_per_arena; i++)
00249 {
00250 struct block *b = arena_to_block (a, i);
00251 list_remove (&b->free_elem);
00252 }
00253 palloc_free_page (a);
00254 }
00255
00256 lock_release (&d->lock);
00257 }
00258 else
00259 {
00260
00261 palloc_free_multiple (a, a->free_cnt);
00262 return;
00263 }
00264 }
00265 }
00266
00267
00268 static struct arena *
00269 block_to_arena (struct block *b)
00270 {
00271 struct arena *a = pg_round_down (b);
00272
00273
00274 ASSERT (a != NULL);
00275 ASSERT (a->magic == ARENA_MAGIC);
00276
00277
00278 ASSERT (a->desc == NULL
00279 || (pg_ofs (b) - sizeof *a) % a->desc->block_size == 0);
00280 ASSERT (a->desc != NULL || pg_ofs (b) == sizeof *a);
00281
00282 return a;
00283 }
00284
00285
00286 static struct block *
00287 arena_to_block (struct arena *a, size_t idx)
00288 {
00289 ASSERT (a != NULL);
00290 ASSERT (a->magic == ARENA_MAGIC);
00291 ASSERT (idx < a->desc->blocks_per_arena);
00292 return (struct block *) ((uint8_t *) a
00293 + sizeof *a
00294 + idx * a->desc->block_size);
00295 }