-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalloc.c
More file actions
162 lines (139 loc) · 5.12 KB
/
alloc.c
File metadata and controls
162 lines (139 loc) · 5.12 KB
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
#include "wrapper.h"
#define ALLOCATED 1
#define FREE 0
#define BLOCK_STATE_SIZE 1
#define BLOCK_HEADER_SIZE 5 // block_state + size
#define BLOCK_TAIL_SIZE 4 // pointer to start of block
#define BLOCK_METADATA_SIZE (BLOCK_HEADER_SIZE + BLOCK_TAIL_SIZE)
// writes 4 byte integer
void mwrite4(unsigned int addr, unsigned int val)
{
uint8_t u1 = (uint8_t)(val >> 24);
uint8_t u2 = (uint8_t)(val >> 16);
uint8_t u3 = (uint8_t)(val >> 8);
uint8_t u4 = (uint8_t)(val >> 0);
mwrite(addr, u1);
mwrite(addr + 1, u2);
mwrite(addr + 2, u3);
mwrite(addr + 3, u4);
}
void write_head(unsigned int addr, uint8_t block_state, unsigned int size)
{
mwrite(addr, block_state);
mwrite4(addr + BLOCK_STATE_SIZE, size);
}
void write_tail(unsigned int addr, unsigned int head_pointer)
{
mwrite4(addr, head_pointer);
}
unsigned int mread4(unsigned int addr)
{
uint8_t u1 = mread(addr);
uint8_t u2 = mread(addr + 1);
uint8_t u3 = mread(addr + 2);
uint8_t u4 = mread(addr + 3);
return (unsigned int)u1 << 24 | (unsigned int)u2 << 16 | (unsigned int)u3 << 8 | (unsigned int)u4 << 0;
}
void best_fit(unsigned int searched_size, unsigned int *best_fit_addr, unsigned int *best_fit_block_size)
{
unsigned int block_loc = 0;
while (1)
{
if (block_loc > msize() - 1 - BLOCK_METADATA_SIZE)
break;
uint8_t block_state = mread(block_loc);
unsigned int block_size = mread4(block_loc + BLOCK_STATE_SIZE);
if (block_state == 0 && block_size == 0)
break;
if (block_state == FREE && block_size >= searched_size && (*best_fit_block_size == 0 || block_size < *best_fit_block_size))
{
*best_fit_addr = block_loc;
*best_fit_block_size = block_size;
}
block_loc = block_loc + BLOCK_METADATA_SIZE + block_size;
}
}
void my_init(void)
{
mwrite(0, 0); // 1 byte = block_state
mwrite4(1, msize() - BLOCK_METADATA_SIZE); // 4 bytes = available space
mwrite4(msize() - BLOCK_TAIL_SIZE, 0); // pointer to the start of block (block_state byte)
}
int my_alloc(unsigned int size)
{
// we can not alloc more space than available
if (size > msize() - BLOCK_METADATA_SIZE)
return FAIL;
unsigned int best_fit_addr;
unsigned int best_fit_block_size = 0;
best_fit(size, &best_fit_addr, &best_fit_block_size);
if (best_fit_block_size == 0)
return FAIL;
unsigned int unused_size = best_fit_block_size - size;
if (unused_size > BLOCK_METADATA_SIZE)
{
// alloc required block
write_head(best_fit_addr, ALLOCATED, size);
write_tail(best_fit_addr + BLOCK_HEADER_SIZE + size, best_fit_addr);
// create new free block from unused space
unsigned int unused_block_addr = best_fit_addr + BLOCK_METADATA_SIZE + size;
write_head(unused_block_addr, FREE, unused_size - BLOCK_METADATA_SIZE);
write_tail(unused_block_addr + unused_size - BLOCK_TAIL_SIZE, unused_block_addr);
}
else
{
// if unused space is too small (metadata can not fit), alloc larger block than required to fill up space
write_head(best_fit_addr, ALLOCATED, best_fit_block_size);
write_tail(best_fit_addr + BLOCK_HEADER_SIZE + best_fit_block_size, best_fit_addr);
}
// returns first usable address of block, right after header
return (int)(best_fit_addr + BLOCK_HEADER_SIZE);
}
int my_free(unsigned int addr)
{
// addr validation
unsigned int valid_block_start_addr = 0;
unsigned int valid_block_data_addr = valid_block_start_addr + BLOCK_HEADER_SIZE;
while (1)
{
if (valid_block_data_addr == addr)
break;
if (valid_block_data_addr > addr)
return FAIL;
valid_block_start_addr = valid_block_start_addr + mread4(valid_block_start_addr + BLOCK_STATE_SIZE) + BLOCK_METADATA_SIZE;
valid_block_data_addr = valid_block_start_addr + BLOCK_HEADER_SIZE;
}
// if addr is valid we can proceed further
unsigned int block_start_addr = addr - BLOCK_HEADER_SIZE;
uint8_t block_state = mread(block_start_addr);
if (block_state != ALLOCATED)
return FAIL;
// mark current block as free
mwrite(block_start_addr, FREE);
unsigned int block_size = mread4(block_start_addr + BLOCK_STATE_SIZE);
unsigned int block_tail_addr = block_start_addr + BLOCK_HEADER_SIZE + block_size;
unsigned int next_block_addr = block_start_addr + block_size + BLOCK_METADATA_SIZE;
// if next block is free we can merge it with current block
if (next_block_addr < msize() - 1 - BLOCK_METADATA_SIZE && mread(next_block_addr) == FREE)
{
unsigned int next_block_size = mread4(next_block_addr + BLOCK_STATE_SIZE);
unsigned int next_block_tail_addr = next_block_addr + BLOCK_HEADER_SIZE + next_block_size;
block_size = block_size + next_block_size + BLOCK_METADATA_SIZE;
block_tail_addr = next_block_tail_addr;
write_head(block_start_addr, FREE, block_size);
write_tail(next_block_tail_addr, block_start_addr);
}
// if previous block is free we can merge it with current block
int prev_block_tail_addr = (int)addr - BLOCK_METADATA_SIZE;
if (prev_block_tail_addr > 0)
{
unsigned int prev_block_addr = mread4(block_start_addr - BLOCK_TAIL_SIZE);
if (mread(prev_block_addr) == FREE)
{
unsigned int prev_block_size = mread4(prev_block_addr + BLOCK_STATE_SIZE);
write_head(prev_block_addr, FREE, prev_block_size + block_size + BLOCK_METADATA_SIZE);
write_tail(block_tail_addr, prev_block_addr);
}
}
return OK;
}