summaryrefslogtreecommitdiff
path: root/lib/libc/stdlib/free.c
blob: 40320dc7e48313c47ffdb31242a207bda43f6468 (plain)
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
#include <libc.h>
#include <sys/mman.h>
#include <atomic.h>
#include <malloc.h>
#include <stdint.h>
#include <stdbool.h>

void free(void *ptr)
{
	if (ptr == NULL) {
		return;
	}

	LIBC_LOCK(libc.lock.malloc);

	struct page *p = __malloc_pvec;
	int found_in_pages = 0;

	while (p) {
		if ((uintptr_t)ptr >= (uintptr_t)p->heap &&
		    (uintptr_t)ptr < (uintptr_t)(p->heap + (p->block.size *
							    p->block.count))) {
			size_t offset = (uintptr_t)ptr - (uintptr_t)p->heap;
			size_t index = offset / p->block.size;
			size_t byte_index = index / 8;
			size_t bit_index = index % 8;

			LIBC_LOCK(p->lock);
			if (p->bitmap[byte_index] & (1 << bit_index)) {
				p->bitmap[byte_index] &= ~(1 << bit_index);
				p->block.used--;
				found_in_pages = 1;
			}
			LIBC_UNLOCK(p->lock);

			if (found_in_pages && p->block.used == 0) {
				if (p->prev)
					p->prev->next = p->next;
				if (p->next)
					p->next->prev = p->prev;
				if (p == __malloc_pvec)
					__malloc_pvec = p->next;

				munmap(p, (p->flags == PAGE_SMALL) ?
						  SMALL_PAGE_SIZE :
					  (p->flags == PAGE_MEDIUM) ?
						  MEDIUM_PAGE_SIZE :
						  LARGE_PAGE_SIZE);
			}

			LIBC_UNLOCK(libc.lock.malloc);
			return;
		}
		p = p->next;
	}

	void **orig_ptr_slot = (void **)((uintptr_t)ptr - sizeof(void *));
	void *potential_orig = *orig_ptr_slot;

	p = __malloc_pvec;
	while (p) {
		if ((uintptr_t)potential_orig >= (uintptr_t)p->heap &&
		    (uintptr_t)potential_orig <
			    (uintptr_t)(p->heap +
					(p->block.size * p->block.count))) {
			size_t offset =
				(uintptr_t)potential_orig - (uintptr_t)p->heap;
			size_t index = offset / p->block.size;
			size_t byte_index = index / 8;
			size_t bit_index = index % 8;

			LIBC_LOCK(p->lock);
			if (p->bitmap[byte_index] & (1 << bit_index)) {
				p->bitmap[byte_index] &= ~(1 << bit_index);
				p->block.used--;
			}
			LIBC_UNLOCK(p->lock);

			if (p->block.used == 0) {
				if (p->prev)
					p->prev->next = p->next;
				if (p->next)
					p->next->prev = p->prev;
				if (p == __malloc_pvec)
					__malloc_pvec = p->next;

				munmap(p, (p->flags == PAGE_SMALL) ?
						  SMALL_PAGE_SIZE :
					  (p->flags == PAGE_MEDIUM) ?
						  MEDIUM_PAGE_SIZE :
						  LARGE_PAGE_SIZE);
			}

			LIBC_UNLOCK(libc.lock.malloc);
			return;
		}
		p = p->next;
	}

	LIBC_UNLOCK(libc.lock.malloc);
}