]> git.sur5r.net Git - cc65/blob - libsrc/common/malloc.c
Fixed a bug
[cc65] / libsrc / common / malloc.c
1 /*
2  * malloc.c
3  *
4  * Ullrich von Bassewitz, 03.06.1998
5  */
6
7
8
9 #include <stddef.h>
10 #include "_heap.h"
11
12
13
14 void* malloc (size_t size)
15 /* Allocate memory from the given heap. The function returns a pointer to the
16  * allocated memory block or a NULL pointer if not enough memory is available.
17  * Allocating a zero size block is not allowed.
18  */
19 {
20     struct freeblock* f;
21     unsigned* p;
22
23
24     /* Check for a size of zero, then add the administration space and round
25      * up the size if needed.
26      */
27     if (size == 0) {
28         return 0;
29     }
30     size += HEAP_ADMIN_SPACE;
31     if (size < sizeof (struct freeblock)) {
32         size = sizeof (struct freeblock);
33     }
34
35     /* Search the freelist for a block that is big enough */
36     f = _hfirst;
37     while (f && f->size < size) {
38         f = f->next;
39     }
40
41     /* Did we find one? */
42     if (f) {
43
44         /* We found a block big enough. If the block can hold just the
45          * requested size, use the block in full. Beware: When slicing blocks,
46          * there must be space enough to create a new one! If this is not the
47          * case, then use the complete block.
48          */
49         if (f->size - size < sizeof (struct freeblock)) {
50
51             /* Use the actual size */
52             size = f->size;
53
54             /* Remove the block from the free list */
55             if (f->prev) {
56                 /* We have a previous block */
57                 f->prev->next = f->next;
58             } else {
59                 /* This is the first block, correct the freelist pointer */
60                 _hfirst = f->next;
61             }
62             if (f->next) {
63                 /* We have a next block */
64                 f->next->prev = f->prev;
65             } else {
66                 /* This is the last block, correct the freelist pointer */
67                 _hlast = f->prev;
68             }
69
70         } else {
71
72             /* We must slice the block found. Cut off space from the upper
73              * end, so we can leave the actual free block chain intact.
74              */
75
76             /* Decrement the size of the block */
77             f->size -= size;
78
79             /* Set f to the now unused space above the current block */
80             f = (struct freeblock*) (((unsigned) f) + f->size);
81
82         }
83
84         /* Setup the pointer for the block */
85         p = (unsigned*) f;
86
87     } else {
88
89         /* We did not find a block big enough. Try to use new space from the
90          * heap top.
91          */
92         if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
93             /* Out of heap space */
94             return 0;
95         }
96
97
98         /* There is enough space left, take it from the heap top */
99         p = _hptr;
100         _hptr = (unsigned*) (((unsigned) _hptr) + size);
101
102     }
103
104     /* New block is now in p. Fill in the size and return the user pointer */
105     *p++ = size;
106     return p;
107 }
108
109
110