PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
alloc.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
7# Copyright (c) 2004 adresd <adresd_ps2dev@yahoo.com>
8# Licenced under Academic Free License version 2.0
9# Review ps2sdk README & LICENSE files for further details.
10*/
11
17#include <stdarg.h>
18
19#include "types.h"
20#include "defs.h"
21#include "alloc.h"
22#include "irx_imports.h"
23
24
25#define MODNAME "alloc"
26IRX_ID("Basic alloc library", 1, 1);
27
28extern struct irx_export_table _exp_alloc;
29
30static vs32 alloc_sema = -1;
31
32#define DEFAULT_HEAP_SIZE 128 * 1024
33
34u32 heap_size = DEFAULT_HEAP_SIZE;
35static u8 * heap_start, * heap_end, * _heap_ptr;
36
37static void alloc_lock() {
38 if (alloc_sema >= 0) {
39 WaitSema(alloc_sema);
40 }
41}
42
43static void alloc_unlock() {
44 if (alloc_sema >= 0) {
45 SignalSema(alloc_sema);
46 }
47}
48
49int _start(int argc, char *argv[])
50{
51 iop_sema_t sem_info;
52
53 if (RegisterLibraryEntries(&_exp_alloc) != 0)
54 return MODULE_NO_RESIDENT_END;
55
56 // check arguments for a heap_size parameter.
57 if (argc > 1) {
58 heap_size = strtoul(argv[1], NULL, 0);
59 }
60
61 if (!(heap_start = AllocSysMemory(ALLOC_FIRST, heap_size, NULL)))
62 return MODULE_NO_RESIDENT_END;
63 heap_end = heap_start + heap_size;
64 _heap_ptr = heap_start;
65
66 sem_info.attr = 1;
67 sem_info.option = 1;
68 sem_info.initial = 1;
69 sem_info.max = 1;
70
71 alloc_sema = CreateSema(&sem_info);
72
73 return MODULE_RESIDENT_END;
74}
75
76
77int shutdown()
78{
79 if (alloc_sema >= 0) {
80 DeleteSema(alloc_sema);
81 }
82
83 FreeSysMemory(heap_start);
84
85 return 0;
86}
87
89#define DEFAULT_ALIGNMENT 16
90
91#ifndef ALIGN
92#define ALIGN(x, align) (((x)+((align)-1))&~((align)-1))
93#endif
94
95/* _heap_mem_block_header structure. */
96typedef struct _heap_mem_header {
97 void * ptr;
98 size_t size;
99 struct _heap_mem_header * prev;
100 struct _heap_mem_header * next;
102
103static void * __alloc_heap_base = NULL;
104static heap_mem_header_t *__alloc_heap_head = NULL;
105static heap_mem_header_t *__alloc_heap_tail = NULL;
106
107static void * alloc_sbrk(size_t increment)
108{
109 u8 *mp, *ret = (void *)-1;
110
111 if (increment == 0)
112 return _heap_ptr;
113
114 /* If the area we want to allocated is past the end of our heap, we have a problem. */
115 mp = _heap_ptr + increment;
116 if (mp <= heap_end) {
117 ret = _heap_ptr;
118 _heap_ptr = mp;
119 }
120
121 return ret;
122}
123
126{
127 heap_mem_header_t *prev_mem = head;
128 u32 prev_top, next_bot;
129
130 while (prev_mem != NULL) {
131 if (prev_mem->next != NULL) {
132 prev_top = (u32)prev_mem->ptr + prev_mem->size;
133 next_bot = (u32)prev_mem->next - prev_top;
134 if (next_bot >= size)
135 return prev_mem;
136 }
137
138 prev_mem = prev_mem->next;
139 }
140
141 return prev_mem;
142}
143
144void * malloc(size_t size)
145{
146 void *ptr = NULL, *mem_ptr;
147 heap_mem_header_t *new_mem, *prev_mem;
148 size_t mem_sz;
149
150 mem_sz = size + sizeof(heap_mem_header_t);
151
152 if ((mem_sz & (DEFAULT_ALIGNMENT - 1)) != 0)
153 mem_sz = ALIGN(mem_sz, DEFAULT_ALIGNMENT);
154
155 alloc_lock();
156
157 /* If we don't have any allocated blocks, reserve the first block from
158 the OS and initialize __alloc_heap_tail. */
159 if (__alloc_heap_head == NULL) {
160 /* Align the bottom of the heap to our default alignment. */
161 if (__alloc_heap_base == NULL) {
162 size_t heap_align_bytes;
163
164 heap_align_bytes = (u32)alloc_sbrk(0) & (DEFAULT_ALIGNMENT - 1);
165 alloc_sbrk(heap_align_bytes);
166 __alloc_heap_base = alloc_sbrk(0);
167 }
168
169 /* Allocate the physical heap and setup the head block. */
170 if ((mem_ptr = alloc_sbrk(mem_sz)) == (void *)-1)
171 return ptr; /* NULL */
172
173 ptr = (void *)((u32)mem_ptr + sizeof(heap_mem_header_t));
174
175 __alloc_heap_head = (heap_mem_header_t *)mem_ptr;
176 __alloc_heap_head->ptr = ptr;
177 __alloc_heap_head->size = mem_sz - sizeof(heap_mem_header_t);
178 __alloc_heap_head->prev = NULL;
179 __alloc_heap_head->next = NULL;
180
181 __alloc_heap_tail = __alloc_heap_head;
182
183 alloc_unlock();
184 return ptr;
185 }
186
187 /* Check to see if there's free space at the bottom of the heap. */
188 if ((void *)((u8 *)__alloc_heap_base + mem_sz) < (void *)__alloc_heap_head) {
189 new_mem = (heap_mem_header_t *)__alloc_heap_base;
190 ptr = (void *)((u32)new_mem + sizeof(heap_mem_header_t));
191
192 new_mem->ptr = ptr;
193 new_mem->size = mem_sz - sizeof(heap_mem_header_t);
194 new_mem->prev = NULL;
195 new_mem->next = __alloc_heap_head;
196 new_mem->next->prev = new_mem;
197 __alloc_heap_head = new_mem;
198
199 alloc_unlock();
200 return ptr;
201 }
202
203 /* See if we can allocate the block without extending the heap. */
204 prev_mem = _heap_mem_fit(__alloc_heap_head, mem_sz);
205 if (prev_mem != NULL) {
206 new_mem = (heap_mem_header_t *)((u32)prev_mem->ptr + prev_mem->size);
207 ptr = (void *)((u32)new_mem + sizeof(heap_mem_header_t));
208
209 new_mem->ptr = ptr;
210 new_mem->size = mem_sz - sizeof(heap_mem_header_t);
211 new_mem->prev = prev_mem;
212 new_mem->next = prev_mem->next;
213 new_mem->next->prev = new_mem;
214 prev_mem->next = new_mem;
215
216 alloc_unlock();
217 return ptr;
218 }
219
220 /* Extend the heap, but make certain the block is inserted in
221 order. */
222 if ((mem_ptr = alloc_sbrk(mem_sz)) == (void *)-1) {
223 alloc_unlock();
224 return ptr; /* NULL */
225 }
226
227 ptr = (void *)((u32)mem_ptr + sizeof(heap_mem_header_t));
228
229 new_mem = (heap_mem_header_t *)mem_ptr;
230 new_mem->ptr = ptr;
231 new_mem->size = mem_sz - sizeof(heap_mem_header_t);
232 new_mem->prev = __alloc_heap_tail;
233 new_mem->next = NULL;
234
235 __alloc_heap_tail->next = new_mem;
236 __alloc_heap_tail = new_mem;
237
238 alloc_unlock();
239 return ptr;
240}
241
242void * realloc(void *ptr, size_t size)
243{
244 heap_mem_header_t *prev_mem;
245 void *new_ptr = NULL;
246
247 if (!size && ptr != NULL) {
248 free(ptr);
249 return new_ptr;
250 }
251
252 if (ptr == NULL)
253 return malloc(size);
254
255 if ((size & (DEFAULT_ALIGNMENT - 1)) != 0)
256 size = ALIGN(size, DEFAULT_ALIGNMENT);
257
258 alloc_lock();
259 prev_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t));
260
261
262 /* Don't do anything if asked for same sized block. */
263 /* If the new size is shorter, let's just shorten the block. */
264 if (prev_mem->size >= size) {
265 /* However, if this is the last block, we have to shrink the heap. */
266 if (!prev_mem->next)
267 alloc_sbrk((u8 *)ptr + size - (u8 *)(alloc_sbrk(0)));
268 prev_mem->size = size;
269
270 alloc_unlock();
271 return ptr;
272 }
273
274
275 /* We are asked for a larger block of memory. */
276
277 /* Are we the last memory block ? */
278 if (!prev_mem->next) {
279 /* Yes, let's just extend the heap then. */
280 if (alloc_sbrk(size - prev_mem->size) == (void*) -1)
281 return NULL;
282 prev_mem->size = size;
283
284 alloc_unlock();
285 return ptr;
286 }
287
288 /* Is the next block far enough so we can extend the current block ? */
289 if ((size_t)(prev_mem->next->ptr - ptr) > size) {
290 prev_mem->size = size;
291
292 alloc_unlock();
293 return ptr;
294 }
295
296 alloc_unlock();
297
298 /* We got out of luck, let's allocate a new block of memory. */
299 if ((new_ptr = malloc(size)) == NULL)
300 return new_ptr;
301
302 /* New block is larger, we only copy the old data. */
303 memcpy(new_ptr, ptr, prev_mem->size);
304
305 free(ptr);
306 return new_ptr;
307}
308
309void * calloc(size_t n, size_t size)
310{
311 void *ptr = NULL;
312 size_t sz = n * size;
313
314 if ((ptr = malloc(sz)) == NULL)
315 return ptr;
316
317 memset(ptr, 0, sz);
318 return ptr;
319}
320
321void * memalign(size_t align, size_t size)
322{
323 heap_mem_header_t new_mem;
324 heap_mem_header_t *cur_mem;
325 heap_mem_header_t *old_mem;
326 void *ptr = NULL;
327
328 if (align <= DEFAULT_ALIGNMENT)
329 return malloc(size);
330
331 /* Allocate with extra alignment bytes just in case it isn't aligned
332 properly by malloc. */
333 if ((ptr = malloc(size + align)) == NULL)
334 return ptr; /* NULL */
335
336 /* If malloc returned it aligned for us we're fine. */
337 if (((u32)ptr & (align - 1)) == 0)
338 return ptr;
339
340 alloc_lock();
341 cur_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t));
342 cur_mem->size -= align;
343
344 /* Otherwise, align the pointer and fixup our hearder accordingly. */
345 ptr = (void *)ALIGN((u32)ptr, align);
346
347 old_mem = cur_mem;
348
349 /* Copy the heap_mem_header_t locally, before repositioning (to make
350 sure we don't overwrite ourselves. */
351 memcpy(&new_mem, cur_mem, sizeof(heap_mem_header_t));
352 cur_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t));
353 memcpy(cur_mem, &new_mem, sizeof(heap_mem_header_t));
354
355 if (cur_mem->prev)
356 cur_mem->prev->next = cur_mem;
357 if (cur_mem->next)
358 cur_mem->next->prev = cur_mem;
359
360 if (__alloc_heap_head == old_mem)
361 __alloc_heap_head = cur_mem;
362
363 if (__alloc_heap_tail == old_mem)
364 __alloc_heap_tail = cur_mem;
365
366 cur_mem->ptr = ptr;
367
368 alloc_unlock();
369 return ptr;
370}
371
372void free(void *ptr)
373{
375 size_t size;
376
377 if (!ptr)
378 return;
379
380 alloc_lock();
381
382 if (!__alloc_heap_head) {
383 alloc_unlock();
384 return;
385 }
386
387
388 /* Freeing the head pointer is a special case. */
389 if (ptr == __alloc_heap_head->ptr) {
390 size = __alloc_heap_head->size +
391 (size_t)(__alloc_heap_head->ptr - (void *)__alloc_heap_head);
392
393 __alloc_heap_head = __alloc_heap_head->next;
394
395 if (__alloc_heap_head != NULL) {
396 __alloc_heap_head->prev = NULL;
397 } else {
398 __alloc_heap_tail = NULL;
399
400 alloc_sbrk(-size);
401 }
402
403 alloc_unlock();
404 return;
405 }
406
407 cur = __alloc_heap_head;
408 while (ptr != cur->ptr) {
409 /* ptr isn't in our list */
410 if (cur->next == NULL) {
411 alloc_unlock();
412 return;
413 }
414
415 cur = cur->next;
416 }
417
418 /* Deallocate the block. */
419 if (cur->next != NULL) {
420 cur->next->prev = cur->prev;
421 } else {
422 void *heap_top;
423
424 /* If this block was the last one in the list, shrink the heap. */
425 __alloc_heap_tail = cur->prev;
426
427 /* We need to free (heap top) - (prev->ptr + prev->size), or else
428 we'll end up with an unallocatable block of heap. */
429 heap_top = alloc_sbrk(0);
430 size = (u32)heap_top - (u32)((u8 *)(cur->prev->ptr) + cur->prev->size);
431 alloc_sbrk(-size);
432 }
433
434 cur->prev->next = cur->next;
435
436 alloc_unlock();
437}
438
439void * __mem_walk_begin() {
440 return __alloc_heap_head;
441}
442
443void __mem_walk_read(void * token, u32 * size, void ** ptr, int * valid) {
444 heap_mem_header_t * cur = (heap_mem_header_t *) token;
445
446 *valid = 1;
447
448 *size = cur->size;
449 *ptr = cur->ptr;
450}
451
452void * __mem_walk_inc(void * token) {
453 heap_mem_header_t * cur = (heap_mem_header_t *) token;
454
455 return cur->next;
456}
457
458int __mem_walk_end(void * token) {
459 return token == NULL;
460}
#define DEFAULT_ALIGNMENT
Definition alloc.c:89
static heap_mem_header_t * _heap_mem_fit(heap_mem_header_t *head, size_t size)
Definition alloc.c:125