PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
heaplib.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "heaplib.h"
12#include "irx_imports.h"
13
14extern struct irx_export_table _exp_heaplib;
15
16#ifdef _IOP
17IRX_ID("Heap_lib", 1, 1);
18#endif
19// Based on the module from SCE SDK 1.3.4.
20
21typedef struct heaplib_ll_
22{
23 struct heaplib_ll_ *next;
24 struct heaplib_ll_ *prev;
25 char payload[];
27
29{
30 struct heaplib_chunk_fragment_ *next_fragment;
31 u32 chunk_size_blks;
32 char payload[];
34
35typedef struct heaplib_chunk_
36{
37 void *chunk_validation_key;
38 u32 free_size;
39 u32 used_size;
40 heaplib_chunk_fragment_t *chunk_fragment_prev;
43
44typedef struct heaplib_heap_
45{
46 void *heap_validation_key;
47 u32 size2free_flags;
49 heaplib_chunk_t mem_chunk;
51
52int _start(int ac, char **av)
53{
54 (void)ac;
55 (void)av;
56
57 return RegisterLibraryEntries(&_exp_heaplib);
58}
59
60static void linked_list_set_self(heaplib_ll_t *ll)
61{
62 ll->next = ll;
63 ll->prev = ll;
64}
65
66#if 0
67static int linked_list_next_is_self(heaplib_ll_t *ll)
68{
69 return ll->next == ll;
70}
71#endif
72
73static void linked_list_remove(heaplib_ll_t *ll)
74{
75 ll->next->prev = ll->prev;
76 ll->prev->next = ll->next;
77}
78
79#if 0
80static int linked_list_is_circular(heaplib_ll_t *ll)
81{
82 return ll->prev == ll->next;
83}
84#endif
85
86static void linked_list_add_after(heaplib_ll_t *ll1, heaplib_ll_t *ll2)
87{
88 ll2->next = ll1;
89 ll2->prev = ll1->prev;
90 ll1->prev = ll2;
91 ll2->prev->next = ll2;
92}
93
94void HeapPrepare(void *mem, int size)
95{
96 u32 calc_size_blks;
98 heaplib_chunk_t *chunk;
99
100 chunk = (heaplib_chunk_t *)mem;
101 if ( chunk )
102 {
103 if ( (unsigned int)size >= 0x29 )
104 {
105 unsigned int calc_size;
106
107 chunk->chunk_validation_key = (((u8 *)chunk) - 1);
108 calc_size = (unsigned int)(size - 16) >> 3;
109 calc_size_blks = calc_size - 1;
110 item = (heaplib_chunk_fragment_t *)(&chunk->used_size + 2 * calc_size);
111 chunk->free_size = size;
112 chunk->chunk_fragment_prev = &chunk->fragment;
113 chunk->used_size = 0;
114 chunk->fragment.chunk_size_blks = calc_size_blks;
115 chunk->fragment.next_fragment = item;
116 item->chunk_size_blks = 0;
117 chunk->fragment.next_fragment->next_fragment = &chunk->fragment;
118 }
119 }
120}
121
122void *heaplib_13_chunk_do_allocate(heaplib_chunk_t *chunk, unsigned int nbytes)
123{
124 void *result;
125 u32 size_calc1;
126 const heaplib_chunk_fragment_t *chunkfrag_prev_1;
127 u32 size_calc2;
128 heaplib_chunk_fragment_t *chunkfrag_prev_2;
129 heaplib_chunk_fragment_t *fragment1;
130 u32 chunk_size_blks;
131 u32 size_subtract;
132
133 if ( !chunk || chunk->chunk_validation_key != (((u8 *)chunk) - 1) )
134 return 0;
135 size_calc1 = nbytes + 7;
136 if ( nbytes < 8 )
137 size_calc1 = 15;
138 chunkfrag_prev_1 = chunk->chunk_fragment_prev;
139 size_calc2 = (size_calc1 >> 3) + 1;
140 chunkfrag_prev_2 = chunk->chunk_fragment_prev;
141 for ( fragment1 = chunkfrag_prev_2->next_fragment;; fragment1 = fragment1->next_fragment )
142 {
143 chunk_size_blks = fragment1->chunk_size_blks;
144 if ( (int)chunk_size_blks >= (int)size_calc2 )
145 break;
146 chunkfrag_prev_2 = fragment1;
147 if ( fragment1 == chunkfrag_prev_1 )
148 return 0;
149 }
150 size_subtract = chunk_size_blks - size_calc2;
151 if ( chunk_size_blks == size_calc2 )
152 {
153 chunkfrag_prev_2->next_fragment = fragment1->next_fragment;
154 }
155 else
156 {
157 fragment1->chunk_size_blks = size_subtract;
158 fragment1 += size_subtract;
159 fragment1->chunk_size_blks = size_calc2;
160 }
161 chunk->chunk_fragment_prev = chunkfrag_prev_2;
162 fragment1->next_fragment = (heaplib_chunk_fragment_t *)chunk;
163 result = fragment1->payload;
164 chunk->used_size += fragment1->chunk_size_blks;
165 return result;
166}
167
168int heaplib_14_chunk_do_iterate(heaplib_chunk_t *chunk, void *ptr)
169{
170 heaplib_chunk_fragment_t *chunk_header;
171 heaplib_chunk_fragment_t *fragment1;
172 const heaplib_chunk_fragment_t *fragment2;
173 const heaplib_chunk_fragment_t *next_chunk;
174 u32 chunk_size_blks2;
175
176 if ( !chunk || chunk->chunk_validation_key != (((u8 *)chunk) - 1) )
177 return -4;
178 if ( !ptr )
179 return -1;
180 chunk_header = (heaplib_chunk_fragment_t *)((char *)ptr - 8);
181 if ( *((heaplib_chunk_t **)ptr - 2) != chunk || (int)chunk_header->chunk_size_blks <= 0 )
182 return -1;
183 if (
184 chunk_header < &chunk->fragment || chunk_header >= (heaplib_chunk_fragment_t *)((char *)chunk + chunk->free_size) )
185 return -2;
186 fragment1 = chunk->chunk_fragment_prev;
187 if ( fragment1 >= chunk_header || chunk_header >= fragment1->next_fragment )
188 {
189 while ( chunk_header != fragment1 )
190 {
191 fragment2 = fragment1->next_fragment;
192 if ( fragment1 < fragment1->next_fragment )
193 goto lbl18;
194 if ( chunk_header < fragment1->next_fragment )
195 goto lbl20;
196 if ( fragment1 >= chunk_header )
197 {
198 lbl18:
199 fragment1 = fragment1->next_fragment;
200 if ( fragment2 >= chunk_header || chunk_header >= fragment2->next_fragment )
201 continue;
202 }
203 if ( chunk_header >= fragment1->next_fragment )
204 goto lbl21;
205 goto lbl20;
206 }
207 return -3;
208 }
209lbl20:
210 if ( fragment1->next_fragment < &chunk_header[chunk_header->chunk_size_blks] )
211 return -3;
212lbl21:
213 if ( fragment1 < chunk_header && chunk_header < &fragment1[fragment1->chunk_size_blks] )
214 return -3;
215 chunk->used_size -= chunk_header->chunk_size_blks;
216 next_chunk = &chunk_header[chunk_header->chunk_size_blks];
217 if (
218 next_chunk != fragment1->next_fragment
219 || (chunk_size_blks2 = next_chunk->chunk_size_blks, (int)chunk_size_blks2 <= 0) )
220 {
221 chunk_header->next_fragment = fragment1->next_fragment;
222 }
223 else
224 {
225 chunk_header->chunk_size_blks += chunk_size_blks2;
226 chunk_header->next_fragment = fragment1->next_fragment->next_fragment;
227 }
228 if ( chunk_header == &fragment1[fragment1->chunk_size_blks] )
229 {
230 fragment1->chunk_size_blks += chunk_header->chunk_size_blks;
231 fragment1->next_fragment = chunk_header->next_fragment;
232 }
233 else
234 {
235 fragment1->next_fragment = chunk_header;
236 }
237 chunk->chunk_fragment_prev = fragment1;
238 return 0;
239}
240
241int heaplib_12_chunk_is_valid(heaplib_chunk_t *chunk)
242{
243 return chunk && chunk->chunk_validation_key == (((u8 *)chunk) - 1) && chunk->used_size == 0;
244}
245
246int HeapChunkSize(void *chunk_)
247{
248 const heaplib_chunk_t *chunk;
249
250 chunk = (heaplib_chunk_t *)chunk_;
251 return 8 * (((chunk->free_size - 16) >> 3) - chunk->used_size - 1);
252}
253
254void *CreateHeap(int heapblocksize, int flag)
255{
256 int calc_size;
257 heaplib_heap_t *heap_new;
258
259 calc_size = 4 * ((heapblocksize + 3) >> 2);
260 heap_new = (heaplib_heap_t *)AllocSysMemory((flag & 2) != 0, calc_size, 0);
261 if ( heap_new )
262 {
263 heap_new->heap_validation_key = (((u8 *)heap_new) + 1);
264 if ( (flag & 1) != 0 )
265 heap_new->size2free_flags = calc_size;
266 else
267 heap_new->size2free_flags = 0;
268 heap_new->size2free_flags |= ((unsigned int)flag >> 1) & 1;
269 linked_list_set_self(&heap_new->l);
270 HeapPrepare(&heap_new->mem_chunk, calc_size - 16);
271 return heap_new;
272 }
273 return 0;
274}
275
276void DeleteHeap(void *heap_)
277{
278 heaplib_ll_t *item;
279 heaplib_ll_t *next;
280 heaplib_heap_t *heap;
281
282 heap = (heaplib_heap_t *)heap_;
283 if ( heap->heap_validation_key == (char *)&heap->heap_validation_key + 1 )
284 {
285 item = heap->l.next;
286 heap->heap_validation_key = 0;
287 if ( item != &heap->l )
288 {
289 do
290 {
291 next = item->next;
292 *(u32 *)item->payload = 0;
293 FreeSysMemory(item);
294 item = next;
295 } while ( next != &heap->l );
296 }
297 heap->mem_chunk.chunk_validation_key = 0;
298 FreeSysMemory(heap);
299 }
300}
301
302void *AllocHeapMemory(void *heap_, size_t nbytes)
303{
304 heaplib_ll_t *item;
305 const heaplib_ll_t *list_head;
306 heaplib_chunk_t *heap_item;
307 int size2free_flags;
308 u32 size_rounded;
309 heaplib_ll_t *heap_new;
310 int BlockSize;
311 heaplib_chunk_t *payload;
312 heaplib_heap_t *heap;
313
314 heap = (heaplib_heap_t *)heap_;
315 if ( heap->heap_validation_key != (((u8 *)heap) + 1) )
316 return 0;
317 item = heap->l.next;
318 list_head = &heap->l;
319 for ( heap_item = (heaplib_chunk_t *)item->payload;; heap_item = (heaplib_chunk_t *)item->payload )
320 {
321 void *result;
322
323 result = heaplib_13_chunk_do_allocate(heap_item, nbytes);
324 if ( result )
325 return result;
326 if ( item == list_head )
327 {
328 size2free_flags = heap->size2free_flags;
329 if ( size2free_flags >= 4 )
330 {
331 size_rounded = 2 * (size2free_flags >> 1);
332 if ( (int)(size_rounded - 40) < (int)(nbytes) )
333 size_rounded = nbytes + 40;
334 heap_new = (heaplib_ll_t *)AllocSysMemory(heap->size2free_flags & 1, size_rounded, 0);
335 if ( heap_new )
336 {
337 BlockSize = QueryBlockSize(heap_new);
338 linked_list_add_after(heap->l.next, heap_new);
339 payload = (heaplib_chunk_t *)heap_new->payload;
340 HeapPrepare(payload, BlockSize - 8);
341 return heaplib_13_chunk_do_allocate(payload, nbytes);
342 }
343 }
344 return 0;
345 }
346 item = item->next;
347 }
348 return 0;
349}
350
351int FreeHeapMemory(void *heap_, void *ptr)
352{
353 const heaplib_ll_t *list_head;
354 heaplib_ll_t *item;
355 heaplib_chunk_t *chunk_item;
356 heaplib_heap_t *heap;
357
358 heap = (heaplib_heap_t *)heap_;
359 if ( !heap )
360 return -4;
361 list_head = &heap->l;
362 if ( heap->heap_validation_key != (((u8 *)heap) + 1) )
363 return -4;
364 item = heap->l.next;
365 for ( chunk_item = (heaplib_chunk_t *)item->payload; heaplib_14_chunk_do_iterate(chunk_item, ptr);
366 chunk_item = (heaplib_chunk_t *)item->payload )
367 {
368 if ( item == list_head )
369 return -1;
370 item = item->next;
371 }
372 if ( item != list_head && heaplib_12_chunk_is_valid(chunk_item) != 0 )
373 {
374 linked_list_remove(item);
375 *(u32 *)item->payload = 0;
376 FreeSysMemory(item);
377 }
378 return 0;
379}
380
381int HeapTotalFreeSize(void *heap_)
382{
383 int calc_size;
385 heaplib_ll_t *chunk_item;
386 heaplib_heap_t *heap;
387
388 heap = (heaplib_heap_t *)heap_;
389 calc_size = 0;
390 if ( !heap )
391 return -4;
392 list_head = &heap->l;
393 if ( heap->heap_validation_key != (((u8 *)heap) + 1) )
394 return -4;
395 for ( chunk_item = heap->l.next;; chunk_item = chunk_item->next )
396 {
397 calc_size += HeapChunkSize((heaplib_chunk_t *)chunk_item->payload);
398 if ( chunk_item == list_head )
399 break;
400 }
401 return calc_size;
402}