-
Notifications
You must be signed in to change notification settings - Fork 6
/
free.c
89 lines (83 loc) · 2.44 KB
/
free.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
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include "malloc.c"
#include "include/free.h"
/*
* This file contains the implementaion of the function free()
* For the details on few data structs such as meta_block and meta_ptr refer to the file malloc.c
*/
/* The function merge_block() checks if the next block is free and merges it with the block passed as an argument */
meta_ptr merge_blocks(meta_ptr block)
{
if (block->next && block->next->free)
{
block->size += META_BLOCK_SIZE + block->next->size;
block->next = block->next->next;
}
if (block->next)
{
block->next->prev = block;
}
return block;
}
/* The function get_block_addr() returns the address of the meta_block from taking the addr of data as an argument.
* Type casing the passed void pointer to char pointer and subtracting the size of the meta_block will give us the required address.
*/
meta_ptr get_block_addr(void *p)
{
char *tmp = p;
tmp = tmp - META_BLOCK_SIZE;
p = tmp;
return (p);
}
/*
* This function checks if the given pointer address is indeed created by invoking malloc() or not.
* We use the field ptr in the meta_block() to check if the passed address is same as the one present in the meta_block()
*/
int is_addr_valid(void *p)
{
if (base)
{
if (p > base && p < sbrk(0))
{
return (p == get_block_addr(p)->ptr);
}
}
return 0;
}
/*
* The pointer is first checked if valid. If it's valid we set the free field value of the block to 1
* Then if the previous block exists, it is checked if its free and then merged with the current block.
* Same is done for the next block also.
* And finally if the freed block is at the end of the linkedlist, it is removed from the linkedlist and the break line
* of the heap is set to the corresponding last address in the linkedlist using the syscall brk()
*/
void free(void *ptr)
{
if (is_addr_valid(ptr))
{
meta_ptr block = get_block_addr(ptr);
block->free = 1;
if (block->prev && block->prev->free)
{
block = merge_blocks(block->prev);
}
if (block->next)
{
block = merge_blocks(block);
}
else
{
if (block->prev)
{
block->prev->next = NULL;
}
else
{
base = NULL;
}
brk(block);
}
}
}