-
Notifications
You must be signed in to change notification settings - Fork 0
/
myalloc.c
executable file
·250 lines (231 loc) · 9.67 KB
/
myalloc.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#include "myalloc.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
// Included list structure for the free and allocated memory lists
#include "list.h"
#define HEADER_SIZE 8 // Size of the header
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // Mutex for thread safety of the allocator
struct Myalloc
{
enum allocation_algorithm aalgorithm;
int size;
void *memory;
// Some other data members you want, such as lists to record allocated/free memory
struct memoryBlock *allocated, *free;
};
struct Myalloc myalloc;
void init_free_memory()
{
memset(myalloc.memory, 0, myalloc.size); // Initialize memory to 0
// Add the initial header to the free list
struct memoryBlock *chunk = List_createBlock(myalloc.memory + HEADER_SIZE);
List_insertBlock(&myalloc.free, chunk);
// Add the size of header to the memory
size_t header = myalloc.size - HEADER_SIZE;
memcpy(myalloc.memory, &header, HEADER_SIZE);
}
void initialize_allocator(int _size, enum allocation_algorithm _aalgorithm)
{
assert(_size > 0);
myalloc.aalgorithm = _aalgorithm;
myalloc.size = _size;
myalloc.memory = malloc((size_t)myalloc.size);
// Add some other initialization
pthread_mutex_init(&mutex, NULL); // Initialize mutex
myalloc.allocated = NULL; // Initialize allocated list to NULL
init_free_memory(); // Initialize free memory list
}
void destroy_allocator()
{
free(myalloc.memory);
// free other dynamic allocated memory to avoid memory leak
List_destroy(&myalloc.allocated); // Destroy allocated memory list
List_destroy(&myalloc.free); // Destroy free memory list
pthread_mutex_unlock(&mutex); // Unlock mutex before destroying
pthread_mutex_destroy(&mutex); // Destroy mutex
}
// Helper function to allocate memory in the allocate function
void *allocator(int _size, struct memoryBlock *block)
{
size_t remainder_size = 0;
// Check if the size of the block is greater than the size of the memory requested plus the size of the header
if (List_getSize(block->size - HEADER_SIZE) >= _size + HEADER_SIZE)
{
size_t header = List_getSize(block->size - HEADER_SIZE) - _size - HEADER_SIZE;
memcpy(block->size + _size, &header, HEADER_SIZE);
struct memoryBlock *newnode = List_createBlock(block->size + _size + HEADER_SIZE);
List_insertBlock(&myalloc.free, newnode);
}
else
remainder_size = List_getSize(block->size - HEADER_SIZE);
// Remove block from free list and add to allocated list
List_deleteBlock(&myalloc.free, block);
List_insertBlock(&myalloc.allocated, block);
// Set the header of the allocated block to the size of the memory requested plus the remainder
*(size_t *)(block->size - HEADER_SIZE) = _size + remainder_size;
return block->size;
}
void *allocate(int _size)
{
void *ptr = NULL;
// Allocate memory from myalloc.memory
// ptr = address of allocated memory
assert(_size > 0); // Assert that the size of the memory requested is greater than 0
pthread_mutex_lock(&mutex); // Lock mutex before allocating
struct memoryBlock *current = myalloc.free;
struct memoryBlock *temp_block = NULL;
if (myalloc.aalgorithm == FIRST_FIT)
{
while (current != NULL)
{
// Check if the size of the block is greater than or equal to the size of the memory requested
if (List_getSizeInt(current->size - HEADER_SIZE) >= _size)
{
ptr = allocator(_size, current); // Allocate the first fit entry
break;
}
current = current->next;
}
}
else if (myalloc.aalgorithm == WORST_FIT)
{
int fragment_size = 0;
while (current != NULL)
{
// Check if the size of the block is greater than or equal to the size of the memory requested and if the fragment is larger than the current worst fragment
if (List_getSize(current->size - HEADER_SIZE) >= _size && List_getSizeInt(current->size - HEADER_SIZE) >= _size + fragment_size)
{
fragment_size = List_getSize(current->size) - _size;
temp_block = current;
}
current = current->next;
}
if (temp_block != NULL)
ptr = allocator(_size, temp_block); // Allocate the worst fit entry
}
else if (myalloc.aalgorithm == BEST_FIT)
{
int fragment_size = myalloc.size;
while (current != NULL)
{
// Check if the size of the block is greater than or equal to the size of the memory requested and if the fragment is smaller than the current best fragment
if (List_getSize(current->size - HEADER_SIZE) >= _size && List_getSizeInt(current->size - HEADER_SIZE) <= _size + fragment_size)
{
fragment_size = List_getSize(current->size) - _size;
temp_block = current;
}
current = current->next;
}
if (temp_block != NULL)
ptr = allocator(_size, temp_block); // Allocate the best fit entry
}
pthread_mutex_unlock(&mutex); // Unlock mutex after allocating
return ptr; // Return the pointer to the allocated memory
}
void deallocate(void *_ptr)
{
assert(_ptr != NULL);
// Free allocated memory
// Note: _ptr points to the user-visible memory. The size information is
// stored at (char*)_ptr - 8.
pthread_mutex_lock(&mutex); // Lock mutex before deallocation
struct memoryBlock *temp = List_findBlock(myalloc.allocated, _ptr); // Find the block in the allocated list
List_deleteBlock(&myalloc.allocated, temp); // Remove the block from the allocated list
List_insertBlock(&myalloc.free, temp); // Add the block to the free list
// If the allocated list is empty we clear the free list and reinitialize it
if (myalloc.allocated == NULL)
{
List_destroy(&myalloc.free);
init_free_memory();
}
// While the next block is free we merge the blocks
struct memoryBlock *current = myalloc.free;
while (current->next != NULL)
{
size_t current_size = List_getSize(current->size - HEADER_SIZE) + HEADER_SIZE;
if (current->size + current_size == current->next->size)
{
*(size_t *)(current->size - HEADER_SIZE) += List_getSize(current->next->size - HEADER_SIZE);
List_freeBlock(&myalloc.free, List_findBlock(myalloc.free, current->next->size));
continue;
}
current = current->next;
}
pthread_mutex_unlock(&mutex); // Unlock mutex after deallocation
}
int compact_allocation(void **_before, void **_after)
{
int compacted_size = 0;
// compact allocated memory
// update _before, _after and compacted_size
pthread_mutex_lock(&mutex); // Lock mutex before reallocating
struct memoryBlock *current = myalloc.allocated;
// Moving back the allocated blocks
while (current != NULL)
{
// If the block is not at the start of the memory we move it back
if (myalloc.memory < current->size)
{
_before[compacted_size] = current->size;
_after[compacted_size] = current->size;
compacted_size += 1;
}
current = current->next;
}
// Adding the free block to the end of the allocated blocks
struct memoryBlock *temp = List_createBlock(myalloc.memory + HEADER_SIZE);
List_insertBlock(&myalloc.free, temp);
memcpy(myalloc.memory, &myalloc.size, HEADER_SIZE); // Setting the size of the free block
pthread_mutex_unlock(&mutex); // Unlock mutex after reallocating
return compacted_size;
}
int available_memory()
{
int available_memory_size = 0;
// Calculate available memory size
pthread_mutex_lock(&mutex); // Lock mutex before calculating
struct memoryBlock *current = myalloc.free;
while (current != NULL)
{
available_memory_size += List_getSizeInt(current->size - HEADER_SIZE);
current = current->next;
}
pthread_mutex_unlock(&mutex); // Unlock mutex after calculating
return available_memory_size;
}
void get_statistics(struct Stats *_stat)
{
// Populate struct Stats with the statistics
struct Stats stats;
stats.allocated_size = 0;
stats.allocated_chunks = 0;
stats.free_size = 0;
stats.free_chunks = 0;
stats.largest_free_chunk_size = 0;
pthread_mutex_lock(&mutex); // Lock mutex before accessing memory
stats.smallest_free_chunk_size = myalloc.size;
struct memoryBlock *current_allocated = myalloc.allocated;
struct memoryBlock *current_free = myalloc.free;
// Calculate allocated size and chunks
while (current_allocated != NULL)
{
stats.allocated_size += List_getSizeInt(current_allocated->size - HEADER_SIZE);
stats.allocated_chunks++;
current_allocated = current_allocated->next;
}
// Calculate free size and chunks
while (current_free != NULL)
{
int current_chunk_size = List_getSizeInt(current_free->size - HEADER_SIZE);
stats.free_size += current_chunk_size;
stats.smallest_free_chunk_size = stats.smallest_free_chunk_size < current_chunk_size ? stats.smallest_free_chunk_size : current_chunk_size;
stats.largest_free_chunk_size = stats.largest_free_chunk_size > current_chunk_size ? stats.largest_free_chunk_size : current_chunk_size;
stats.free_chunks++;
current_free = current_free->next;
}
*_stat = stats;
pthread_mutex_unlock(&mutex); // Unlock mutex after accessing memory
}