-
Notifications
You must be signed in to change notification settings - Fork 6
/
malloc.c
153 lines (143 loc) · 4.43 KB
/
malloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "include/malloc.h"
/*
* This implementation of malloc is based on first-fit style.
* meta_block is a struct to store the meta information about every chuck of memory being allocated.
* A doubly-linked list is maintained with all the meta_blocks
* to maintain the space being allocated and deallocated
* Size of meta_block is considered to be 20 (4 bytes for each of the variables).
*/
#define META_BLOCK_SIZE 20
/* The macro align4 is used to set the requested size to multiple of four greater than requested size */
#define align4(x) (((((x)-1) >> 2) << 2) + 4)
/* meta_ptr is a pointer of type meta_block, it is type defined for simplicity and to avoid confusion */
typedef struct meta_block *meta_ptr;
/* base stores the head of the linked list */
void *base = NULL;
/*
* The meta_block contains the variables free, size, next, data.
* free is set to 1 when the respective block is free and vice versa.
* size is used to store the size of the respective block.
* The character array data gives the next address after the
* meta_block as the data variable is defined at last.
* The data variable is made as a character pointer assuming that the character takes 1 byte,
* and so it makes the pointer arithmetic simpler
* The next and prev pointers points to the block in the
* doubly linked list present next and previous to the curr block.
*/
struct meta_block
{
int free;
size_t size;
meta_ptr next;
meta_ptr prev;
void *ptr;
char data[1];
};
/*
* The find_suitable_block function traverses through the linked list
* and find the first block which has space atleast equal to the requested space.
* It also sets the variable last to the address of the last block in the linked-list.
* This comes handy in the malloc function
*/
meta_ptr find_suitable_block(meta_ptr *last, size_t size)
{
meta_ptr b = base;
while (b && !(b->free && b->size >= size))
{
*last = b;
b = b->next;
}
return last;
}
/*
* The split_space function splits the given block if it contains space greater than the requested space.
* Creates a new block of the free space and adds it in the linked list
*/
void split_space(meta_ptr block, size_t size)
{
meta_ptr new_block;
new_block = block->data + size;
new_block->size = block->size - size - META_BLOCK_SIZE;
new_block->next = block->next;
new_block->free = 1;
new_block->ptr = new_block->data;
new_block->prev = block;
block->next = new_block;
block->size = size;
if (new_block->next)
{
new_block->next->prev = new_block;
}
}
/*
* extend_heap() is invoked when the already available blocks of memory is not sutiable or if no block exist already.
* This creates a block of memory near the break of heap.
* The meta_block of the newly created memory block will be added in the last of the linked list.
*/
meta_ptr extend_heap(meta_ptr last, size_t size)
{
meta_ptr old_break, new_break;
old_break = sbrk(0);
new_break = sbrk(META_BLOCK_SIZE + size);
if (new_break == (void *)-1)
{
return NULL;
}
old_break->size = size;
old_break->free = 0;
old_break->next = NULL;
old_break->prev = NULL;
old_break->ptr = old_break->data;
if (last)
{
last->next = old_break;
}
return (old_break);
}
/*
* malloc is the function which will be invoked by the user to allocate space.
* The function first checks if there a memory block with space atleast equal to the requested space.
* If not then it requests a new block to be created from the heap.
* If there are no elements in the linked-list then it asks the heap to allocate memory block
* Finally it return the address from where the data can be stored.
*/
void *malloc(size_t size)
{
meta_ptr block, last;
size_t s;
s = allign4(size);
if (base)
{
last = base;
block = find_suitable_block(&last, s);
if (block)
{
if (block->size - s >= (META_BLOCK_SIZE + 4))
{
split_space(block, s);
}
block->free = 0;
}
else
{
block = extend_heap(last, s);
if (!block)
{
return NULL;
}
}
}
else
{
block = extend_heap(NULL, s);
if (!block)
{
return NULL;
}
base = block;
}
return block->data;
}