version 2.8
gos_x_heap.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.org/license.html
6  */
7 
8 #include "../../gfx.h"
9 
10 #if GOS_NEED_X_HEAP
11 
12 #include <string.h> // Prototype for memcpy()
13 
14 
15 #if GFX_OS_HEAP_SIZE == 0
16  #include <stdlib.h> // Prototype for malloc(), realloc() and free()
17 
18  void _gosHeapInit(void) {
19  }
20  void *gfxAlloc(size_t sz) {
21  return malloc(sz);
22  }
23 
24  void *gfxRealloc(void *ptr, size_t oldsz, size_t newsz) {
25  (void) oldsz;
26  return realloc(ptr, newsz);
27  }
28 
29  void gfxFree(void *ptr) {
30  free(ptr);
31  }
32 
33 #else
34 
35  // Slot structure - user memory follows
36  typedef struct memslot {
37  size_t sz; // Includes the size of this memslot.
38  } memslot;
39 
40  // Free Slot - immediately follows the memslot structure
41  typedef struct freeslot {
42  memslot *nextfree; // The next free slot
43  } freeslot;
44 
45  #define GetSlotSize(sz) ((((sz) + (sizeof(freeslot) - 1)) & ~(sizeof(freeslot) - 1)) + sizeof(memslot))
46  #define NextFree(pslot) ((freeslot *)Slot2Ptr(pslot))->nextfree
47  #define Ptr2Slot(p) ((memslot *)(p) - 1)
48  #define Slot2Ptr(pslot) ((pslot)+1)
49 
50  static memslot * freeSlots;
51  static char heap[GFX_OS_HEAP_SIZE];
52 
53  void _gosHeapInit(void) {
54  gfxAddHeapBlock(heap, GFX_OS_HEAP_SIZE);
55  }
56 
57  void gfxAddHeapBlock(void *ptr, size_t sz) {
58  if (sz < sizeof(memslot)+sizeof(freeslot))
59  return;
60 
61  ((memslot *)ptr)->sz = sz;
62  gfxFree(Slot2Ptr((memslot *)ptr));
63  }
64 
65  void *gfxAlloc(size_t sz) {
66  register memslot *prev, *p, *pnew;
67 
68  if (!sz) return 0;
69  sz = GetSlotSize(sz);
70  for (prev = 0, p = freeSlots; p != 0; prev = p, p = NextFree(p)) {
71  // Loop till we have a block big enough
72  if (p->sz < sz)
73  continue;
74 
75  // Can we save some memory by splitting this block?
76  if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
77  pnew = (memslot *)((char *)p + sz);
78  pnew->sz = p->sz - sz;
79  p->sz = sz;
80  NextFree(pnew) = NextFree(p);
81  NextFree(p) = pnew;
82  }
83 
84  // Remove it from the free list
85  if (prev)
86  NextFree(prev) = NextFree(p);
87  else
88  freeSlots = NextFree(p);
89 
90  // Return the result found
91  return Slot2Ptr(p);
92  }
93  // No slots large enough
94  return 0;
95  }
96 
97  void *gfxRealloc(void *ptr, size_t oldsz, size_t sz) {
98  register memslot *prev, *p, *pfree;
99  (void) oldsz;
100 
101  if (!ptr)
102  return gfxAlloc(sz);
103  if (!sz) {
104  gfxFree(ptr);
105  return 0;
106  }
107 
108  p = Ptr2Slot(ptr);
109  sz = GetSlotSize(sz);
110 
111  // If the next slot is free (and contiguous) merge it into this one
112  for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
113  if (pfree == (memslot *)((char *)p + p->sz)) {
114  p->sz += pfree->sz;
115  if (prev)
116  NextFree(prev) = NextFree(pfree);
117  else
118  freeSlots = NextFree(pfree);
119  break;
120  }
121  }
122 
123  // If this block is large enough we are nearly done
124  if (sz < p->sz) {
125  // Can we save some memory by splitting this block?
126  if (p->sz >= sz + sizeof(memslot)+sizeof(freeslot)) {
127  pfree = (memslot *)((char *)p + sz);
128  pfree->sz = p->sz - sz;
129  p->sz = sz;
130  NextFree(pfree) = freeSlots;
131  freeSlots = pfree;
132  }
133  return Slot2Ptr(p);
134  }
135 
136  // We need to do this the hard way
137  pfree = gfxAlloc(sz);
138  if (pfree)
139  return 0;
140  memcpy(pfree, ptr, p->sz - sizeof(memslot));
141  gfxFree(ptr);
142  return pfree;
143  }
144 
145  void gfxFree(void *ptr) {
146  register memslot *prev, *p, *pfree;
147 
148  if (!ptr)
149  return;
150 
151  p = Ptr2Slot(ptr);
152 
153  // Find a free slot that is contiguous precceding and merge it into us
154  for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
155  if (p == (memslot *)((char *)pfree + pfree->sz)) {
156  pfree->sz += p->sz;
157  if (prev)
158  NextFree(prev) = NextFree(pfree);
159  else
160  freeSlots = NextFree(pfree);
161  p = pfree;
162  break;
163  }
164  }
165 
166  // Find a free slot that is contiguous after and merge it into this one
167  for (prev = 0, pfree = freeSlots; pfree != 0; prev = pfree, pfree = NextFree(pfree)) {
168  if (pfree == (memslot *)((char *)p + p->sz)) {
169  p->sz += pfree->sz;
170  if (prev)
171  NextFree(prev) = NextFree(pfree);
172  else
173  freeSlots = NextFree(pfree);
174  break;
175  }
176  }
177 
178  // Add it into the free chain
179  NextFree(p) = freeSlots;
180  freeSlots = p;
181  }
182 #endif
183 
184 #endif /* GOS_NEED_X_HEAP */
185 
186 #if GFX_EMULATE_MALLOC
187  #include <stdlib.h>
188 
189  void* malloc(size_t size) {
190  return gfxAlloc(size);
191  }
192  void free(void *ptr) {
193  gfxFree(ptr);
194  }
195 #endif
#define GFX_OS_HEAP_SIZE
How much RAM should uGFX use for the heap when using its own internal heap allocator.
Definition: gos_options.h:249
void * gfxAlloc(size_t sz)
Allocate memory.
void * gfxRealloc(void *ptr, size_t oldsz, size_t newsz)
Re-allocate memory.
void gfxFree(void *ptr)
Free memory.