Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
141 Kevin 1
/* 
2
 * Simple, 32-bit and 64-bit clean allocator based on implicit free
3
 * lists, first fit placement, and boundary tag coalescing, as described
4
 * in the CS:APP2e text. Blocks must be aligned to doubleword (8 byte) 
5
 * boundaries. Minimum block size is 16 bytes. 
6
 *
7
 * This version is loosely based on 
8
 * http://csapp.cs.cmu.edu/public/ics2/code/vm/malloc/mm.c
9
 * but unlike the book's version, it does not use C preprocessor 
10
 * macros or explicit bit operations.
11
 */
12
#include <stdio.h>
13
#include <string.h>
14
#include <stdlib.h>
15
#include <stdbool.h>
16
#include <stdint.h>
17
#include <stddef.h>
18
#include <assert.h>
19
 
20
#include "mm.h"
21
#include "memlib.h"
22
 
23
struct boundary_tag {
24
    int inuse:1;        // inuse bit
25
    int size:31;        // size of block, in words
26
};
27
 
28
/* FENCE is used for heap prologue/epilogue. */
29
const struct boundary_tag FENCE = { .inuse = 1, .size = 0 };
30
 
31
/* A C struct describing the beginning of each block. 
32
 * For implicit lists, used and free blocks have the same 
33
 * structure, so one struct will suffice for this example.
34
 * If each block is aligned at 4 mod 8, each payload will
35
 * be aligned at 0 mod 8.
36
 */
37
struct block {
38
    struct boundary_tag header; /* offset 0, at address 4 mod 8 */
39
    char payload[0];            /* offset 4, at address 0 mod 8 */
40
};
41
 
42
/*
43
 * If NEXT_FIT defined use next fit search, else use first fit search 
44
 */
45
#define NEXT_FITx
46
 
47
/* Basic constants and macros */
48
#define WSIZE       4       /* Word and header/footer size (bytes) */
49
#define DSIZE       8       /* Doubleword size (bytes) */
50
#define MIN_BLOCK_SIZE_WORDS 4 /* Minimum block size in words */
51
#define CHUNKSIZE  (1<<10)  /* Extend heap by this amount (words) */
52
 
53
#define MAX(x, y) ((x) > (y)? (x) : (y))  
54
 
55
/* Global variables */
56
static struct block *heap_listp = 0;  /* Pointer to first block */  
57
#ifdef NEXT_FIT
58
static struct block *rover;           /* Next fit rover */
59
#endif
60
 
61
/* Function prototypes for internal helper routines */
62
static struct block *extend_heap(size_t words);
63
static void place(struct block *bp, size_t asize);
64
static struct block *find_fit(size_t asize);
65
static struct block *coalesce(struct block *bp);
66
 
67
/* Given a block, obtain previous's block footer.
68
   Works for left-most block also. */
69
static struct boundary_tag * prev_blk_footer(struct block *blk) {
70
    return &blk->header - 1;
71
}
72
 
73
/* Return if block is free */
74
static bool blk_free(struct block *blk) { 
75
    return !blk->header.inuse; 
76
}
77
 
78
/* Return size of block is free */
79
static size_t blk_size(struct block *blk) { 
80
    return blk->header.size; 
81
}
82
 
83
/* Given a block, obtain pointer to previous block.
84
   Not meaningful for left-most block. */
85
static struct block *prev_blk(struct block *blk) {
86
    struct boundary_tag *prevfooter = prev_blk_footer(blk);
87
    assert(prevfooter->size != 0);
88
    return (struct block *)((size_t *)blk - prevfooter->size);
89
}
90
 
91
/* Given a block, obtain pointer to next block.
92
   Not meaningful for right-most block. */
93
static struct block *next_blk(struct block *blk) {
94
    assert(blk_size(blk) != 0);
95
    return (struct block *)((size_t *)blk + blk->header.size);
96
}
97
 
98
/* Given a block, obtain its footer boundary tag */
99
static struct boundary_tag * get_footer(struct block *blk) {
100
    return (void *)((size_t *)blk + blk->header.size) 
101
                   - sizeof(struct boundary_tag);
102
}
103
 
104
/* Set a block's size and inuse bit in header and footer */
105
static void set_header_and_footer(struct block *blk, int size, int inuse) {
106
    blk->header.inuse = inuse;
107
    blk->header.size = size;
108
    * get_footer(blk) = blk->header;    /* Copy header to footer */
109
}
110
 
111
/* Mark a block as used and set its size. */
112
static void mark_block_used(struct block *blk, int size) {
113
    set_header_and_footer(blk, size, 1);
114
}
115
 
116
/* Mark a block as free and set its size. */
117
static void mark_block_free(struct block *blk, int size) {
118
    set_header_and_footer(blk, size, 0);
119
}
120
 
121
/* 
122
 * mm_init - Initialize the memory manager 
123
 */
124
int mm_init(void) 
125
{
126
    /* Create the initial empty heap */
127
    struct boundary_tag * initial = mem_sbrk(2 * sizeof(struct boundary_tag));
128
    if (initial == (void *)-1)
129
        return -1;
130
 
131
    /* We use a slightly different strategy than suggested in the book.
132
     * Rather than placing a min-sized prologue block at the beginning
133
     * of the heap, we simply place two fences.
134
     * The consequence is that coalesce() must call prev_blk_footer()
135
     * and not prev_blk() - prev_blk() cannot be called on the left-most
136
     * block.
137
     */
138
    initial[0] = FENCE;                     /* Prologue footer */
139
    heap_listp = (struct block *)&initial[1];
140
    initial[1] = FENCE;                     /* Epilogue header */
141
 
142
#ifdef NEXT_FIT
143
    rover = heap_listp;
144
#endif
145
 
146
    /* Extend the empty heap with a free block of CHUNKSIZE bytes */
147
    if (extend_heap(CHUNKSIZE) == NULL) 
148
        return -1;
149
    return 0;
150
}
151
 
152
/* 
153
 * mm_malloc - Allocate a block with at least size bytes of payload 
154
 */
155
void *mm_malloc(size_t size)
156
{
157
    size_t awords;      /* Adjusted block size in words */
158
    size_t extendwords;  /* Amount to extend heap if no fit */
159
    struct block *bp;      
160
 
161
    if (heap_listp == 0){
162
        mm_init();
163
    }
164
    /* Ignore spurious requests */
165
    if (size == 0)
166
        return NULL;
167
 
168
    /* Adjust block size to include overhead and alignment reqs. */
169
    size += 2 * sizeof(struct boundary_tag);    /* account for tags */
170
    size = (size + DSIZE - 1) & ~(DSIZE - 1);   /* align to double word */
171
    awords = MAX(MIN_BLOCK_SIZE_WORDS, size/WSIZE);
172
                                                /* respect minimum size */
173
 
174
    /* Search the free list for a fit */
175
    if ((bp = find_fit(awords)) != NULL) {
176
        place(bp, awords);
177
        return bp->payload;
178
    }
179
 
180
    /* No fit found. Get more memory and place the block */
181
    extendwords = MAX(awords,CHUNKSIZE);
182
    if ((bp = extend_heap(extendwords)) == NULL)  
183
        return NULL;
184
    place(bp, awords);
185
    return bp->payload;
186
} 
187
 
188
/* 
189
 * mm_free - Free a block 
190
 */
191
void mm_free(void *bp)
192
{
193
    if (bp == 0) 
194
        return;
195
 
196
    /* Find block from user pointer */
197
    struct block *blk = bp - offsetof(struct block, payload);
198
    if (heap_listp == 0) {
199
        mm_init();
200
    }
201
 
202
    mark_block_free(blk, blk_size(blk));
203
    coalesce(blk);
204
}
205
 
206
/*
207
 * coalesce - Boundary tag coalescing. Return ptr to coalesced block
208
 */
209
static struct block *coalesce(struct block *bp) 
210
{
211
    bool prev_alloc = prev_blk_footer(bp)->inuse;
212
    bool next_alloc = ! blk_free(next_blk(bp));
213
    size_t size = blk_size(bp);
214
 
215
    if (prev_alloc && next_alloc) {            /* Case 1 */
216
        return bp;
217
    }
218
 
219
    else if (prev_alloc && !next_alloc) {      /* Case 2 */
220
        mark_block_free(bp, size + blk_size(next_blk(bp)));
221
    }
222
 
223
    else if (!prev_alloc && next_alloc) {      /* Case 3 */
224
        bp = prev_blk(bp);
225
        mark_block_free(bp, size + blk_size(bp));
226
    }
227
 
228
    else {                                     /* Case 4 */
229
        mark_block_free(prev_blk(bp), 
230
                        size + blk_size(next_blk(bp)) + blk_size(prev_blk(bp)));
231
        bp = prev_blk(bp);
232
    }
233
#ifdef NEXT_FIT
234
    /* Make sure the rover isn't pointing into the free block */
235
    /* that we just coalesced */
236
    if ((rover > bp) && (rover < next_blk(bp))) 
237
        rover = bp;
238
#endif
239
    return bp;
240
}
241
 
242
/*
243
 * mm_realloc - Naive implementation of realloc
244
 */
245
void *mm_realloc(void *ptr, size_t size)
246
{
247
    size_t oldsize;
248
    void *newptr;
249
 
250
    /* If size == 0 then this is just free, and we return NULL. */
251
    if(size == 0) {
252
        mm_free(ptr);
253
        return 0;
254
    }
255
 
256
    /* If oldptr is NULL, then this is just malloc. */
257
    if(ptr == NULL) {
258
        return mm_malloc(size);
259
    }
260
 
261
    newptr = mm_malloc(size);
262
 
263
    /* If realloc() fails the original block is left untouched  */
264
    if(!newptr) {
265
        return 0;
266
    }
267
 
268
    /* Copy the old data. */
269
    struct block *oldblock = ptr - offsetof(struct block, payload);
270
    oldsize = blk_size(oldblock) * WSIZE;
271
    if(size < oldsize) oldsize = size;
272
    memcpy(newptr, ptr, oldsize);
273
 
274
    /* Free the old block. */
275
    mm_free(ptr);
276
 
277
    return newptr;
278
}
279
 
280
/* 
281
 * checkheap - We don't check anything right now. 
282
 */
283
void mm_checkheap(int verbose)  
284
{ 
285
}
286
 
287
/* 
288
 * The remaining routines are internal helper routines 
289
 */
290
 
291
/* 
292
 * extend_heap - Extend heap with free block and return its block pointer
293
 */
294
static struct block *extend_heap(size_t words) 
295
{
296
    void *bp;
297
 
298
    /* Allocate an even number of words to maintain alignment */
299
    words = (words + 1) & ~1;
300
    if ((long)(bp = mem_sbrk(words * WSIZE)) == -1)  
301
        return NULL;
302
 
303
    /* Initialize free block header/footer and the epilogue header.
304
     * Note that we scoop up the previous epilogue here. */
305
    struct block * blk = bp - sizeof(FENCE);
306
    mark_block_free(blk, words);
307
    next_blk(blk)->header = FENCE;
308
 
309
    /* Coalesce if the previous block was free */
310
    return coalesce(blk);
311
}
312
 
313
/* 
314
 * place - Place block of asize words at start of free block bp 
315
 *         and split if remainder would be at least minimum block size
316
 */
317
static void place(struct block *bp, size_t asize)
318
{
319
    size_t csize = blk_size(bp);
320
 
321
    if ((csize - asize) >= MIN_BLOCK_SIZE_WORDS) { 
322
        mark_block_used(bp, asize);
323
        bp = next_blk(bp);
324
        mark_block_free(bp, csize-asize);
325
    }
326
    else { 
327
        mark_block_used(bp, csize);
328
    }
329
}
330
 
331
/* 
332
 * find_fit - Find a fit for a block with asize words 
333
 */
334
static struct block *find_fit(size_t asize)
335
{
336
 
337
#ifdef NEXT_FIT 
338
    /* Next fit search */
339
    struct block *oldrover = rover;
340
 
341
    /* Search from the rover to the end of list */
342
    for ( ; blk_size(rover) > 0; rover = next_blk(rover))
343
        if (blk_free(rover) && (asize <= blk_size(rover)))
344
            return rover;
345
 
346
    /* search from start of list to old rover */
347
    for (rover = heap_listp; rover < oldrover; rover = next_blk(rover))
348
        if (blk_free(rover) && (asize <= blk_size(rover)))
349
            return rover;
350
 
351
    return NULL;  /* no fit found */
352
#else 
353
    /* First fit search */
354
    struct block *bp;
355
 
356
    for (bp = heap_listp; blk_size(bp) > 0; bp = next_blk(bp)) {
357
        if (blk_free(bp) && asize <= blk_size(bp)) {
358
            return bp;
359
        }
360
    }
361
    return NULL; /* No fit */
362
#endif
363
}
364
 
365
team_t team = {
366
    /* Team name */
367
    "Sample allocator using implicit lists",
368
    /* First member's full name */
369
    "Godmar Back",
370
    "gback@cs.vt.edu",
371
    /* Second member's full name (leave blank if none) */
372
    "",
373
    "",
374
};