MushOS  0.1
A UNIX-like OS prototype, written from scratch
Loading...
Searching...
No Matches
lib/base/heap.c
Go to the documentation of this file.
1/**
2 * @file
3 *
4 * @brief This is a standard implementation of heap for MushLib.
5 *
6 * The heap doesn't use paging, so it has a limited size.
7 * This allows kernel to use it right after launch, but there's also a significant drawback:
8 * when kernel heap gets overflown, no standard exception can be shown (because it requires heap space allocation).
9 * The drawback is handled with @link core/kernel/heap.c kernel allocation exception handler @endlink.
10 * Any non-kernel apps may set up their own kernel exception handler (using @ref allocation_exception_id)
11 * or just do nothing - default allocation exception handler will allow kernel to terminate safely any app with overflown heap.
12 */
13
14#include "heap.h"
15
16#include "memory.h"
17#include "exceptions.h"
18
19
20/**
21 * Header of the heap.
22 * Defines current heap: its start and end addresses and address of the first allocated block.
23 * Located in the very beginning of the heap.
24 */
25typedef struct {
26 void* first_address;
27 void* heap_start, * heap_end;
29
30/**
31 * Header of an allocated heap block.
32 * Defines current block, contain its size.
33 * Also acts as a linked list, contains addresses of the previous and next allocated blocks.
34 */
35typedef struct {
36 u_dword size;
37 void* previous, * next;
39
40
41/**
42 * Header of the current app heap.
43 * Every app in MushOS has its own heap.
44 * This implementation of heap is a singleton.
45 */
47
48
49boolean is_in_heap(void* structure) {
50 return structure > header->heap_start && structure < header->heap_end;
51}
52
53/**
54 * Internal function for getting heap header of any structure located in heap.
55 * It just substracts heap block header size from pointer and casts it to heap block header.
56 * Throws heap exception if the given pointer is outside of the current heap.
57 * @param structure a pointer to the structure.
58 * @return heap_block_header pointer.
59 */
60static heap_block_header* get_header(void* structure) {
61 if (is_in_heap(structure)) return (heap_block_header*) (structure - sizeof(heap_block_header));
62 else throw_verbose(heap_exception_id, heap_exception_type, "Requested structure is located outside of the heap!")
63}
64
65u_dword size(void* structure) {
66 return get_header(structure)->size;
67}
68
69precise occupation() {
70 if (!header->first_address) return 0.0;
71 u_dword sum = 0;
72 u_dword num = 0;
73
74 void* current_address = header->first_address;
75 while (current_address) {
76 heap_block_header* current_block = get_header(current_address);
77 sum += current_block->size;
78 num++;
79 current_address = current_block->next;
80 }
81
82 return (precise) num;
83}
84
85
86/**
87 * Internal function for space allocation in heap.
88 * Sets up and fills heap block header, optionally alters headers of the next and previous heap blocks.
89 * @param free_pointer pointer to free space (heap block header size + required size).
90 * @param size required size of heap block.
91 * @param previous previous heap block.
92 * @param next next heap block.
93 * @return pointer to the start of the block.
94 */
95static void* allocate_space(void* free_pointer, u_dword size, heap_block_header* previous, heap_block_header* next) {
96 ((heap_block_header*) free_pointer)->size = size;
97 ((heap_block_header*) free_pointer)->previous = previous;
98 ((heap_block_header*) free_pointer)->next = next;
99
100 void* memory_address = free_pointer + sizeof(heap_block_header);
101 if (previous) get_header(previous)->next = memory_address;
102 if (next) get_header(next)->previous = memory_address;
103 return memory_address;
104}
105
106
107/**
108 * Allocation exception can't be handled regularily: handling requires heap.
109 * So, heap exception terminate app without any on-screen explanation.
110 */
112 terminate(heap_exception_id);
113}
114
115
116void initialize_heap(void* start_address, u_dword initial_size) {
117 header = start_address;
118 memory_clear(start_address, sizeof(heap_header), 0);
119 header->heap_start = start_address + sizeof(heap_header);
120 header->heap_end = start_address + initial_size;
121 header->first_address = nullptr;
123}
124
125void* ralloc(u_dword size) {
126 if (!header->first_address) {
127 header->first_address = allocate_space(header->heap_start, size, nullptr, nullptr);
128 return header->first_address;
129 }
130
131 void* best_address = nullptr, * best_previous = nullptr, * best_next = nullptr;
132 u_dword best_size = header->heap_end - header->heap_start;
133
134 void* current_address = header->heap_start;
135 void* next_address = header->first_address;
136
137 u_dword free_space_size = next_address - current_address - sizeof(heap_block_header);
138 if ((free_space_size >= (size + sizeof(heap_block_header))) && (free_space_size < best_size)) {
139 best_size = free_space_size;
140 best_address = current_address; best_previous = nullptr; best_next = next_address;
141 }
142
143 current_address = next_address;
144 heap_block_header* current_block = get_header(current_address);
145 next_address = current_block->next;
146
147 while (next_address) {
148 free_space_size = next_address - current_address - current_block->size - sizeof(heap_block_header);
149 if ((free_space_size >= (size + sizeof(heap_block_header))) && (free_space_size < best_size)) {
150 best_size = free_space_size;
151 best_address = current_address + current_block->size; best_previous = current_address; best_next = next_address;
152 }
153
154 current_address = next_address;
155 current_block = get_header(current_address);
156 next_address = current_block->next;
157 }
158
159 free_space_size = header->heap_end - current_address - current_block->size - sizeof(heap_block_header);
160 if ((free_space_size >= (size + sizeof(heap_block_header))) && (free_space_size < best_size)) {
161 best_address = current_address + current_block->size; best_previous = current_address; best_next = nullptr;
162 }
163
164 void* final_address = nullptr;
165 if (best_address != nullptr) final_address = allocate_space(best_address, size, best_previous, best_next);
166 if (best_address == header->heap_start) header->first_address = final_address;
167 if (final_address == nullptr) throw_verbose(allocation_exception_id, allocation_exception_type, "No space left in heap available for allocation!")
168 return final_address;
169}
170
171void* zalloc(u_dword size) {
172 void* result = ralloc(size);
173 memory_clear((byte*) result, size, 0);
174 return result;
175}
176
177void* challoc(void* structure, u_dword new_size) {
178 heap_block_header* block = get_header(structure);
179 if (new_size < block->size) {
180 block->size = new_size;
181 } else if (new_size > block->size) {
182 if (new_size < block->next - structure) block->size = new_size;
183 else {
184 void* new_structure = ralloc(new_size);
185 memory_copy(structure, new_structure, block->size);
186 unalloc(structure);
187 structure = new_structure;
188 }
189 }
190 return structure;
191}
192
193void unalloc(void* structure) {
194 heap_block_header* block = get_header(structure);
195 if (structure == header->first_address) header->first_address = block->next;
196 if (block->next) get_header(block->next)->previous = block->previous;
197 if (block->previous) get_header(block->previous)->next = block->next;
198}
This is a standard MushLib heap header. See standard implementation in lib/base/heap....
#define heap_exception_id
Definition: heap.h:38
#define allocation_exception_id
Definition: heap.h:25
#define allocation_exception_type
Definition: heap.h:30
#define heap_exception_type
Definition: heap.h:43
void * ralloc(u_dword size)
void unalloc(void *structure)
precise occupation()
Definition: lib/base/heap.c:69
u_dword size(void *structure)
Definition: lib/base/heap.c:65
void * zalloc(u_dword size)
void * challoc(void *structure, u_dword new_size)
static void handle_allocation_exception()
void initialize_heap(void *start_address, u_dword initial_size)
static heap_block_header * get_header(void *structure)
Definition: lib/base/heap.c:60
heap_header * header
Definition: lib/base/heap.c:46
static void * allocate_space(void *free_pointer, u_dword size, heap_block_header *previous, heap_block_header *next)
Definition: lib/base/heap.c:95
boolean is_in_heap(void *structure)
Definition: lib/base/heap.c:49