embkernel
 All Classes Functions Variables Typedefs Groups Pages
LibDmem.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "LibDmem.hpp"
7 #include <stdint.h>
8 #include <string.h>
9 
10 LibDmem::LibDmem(void* buffer, size_t size) {
11  mBeginning = (SEGMENT*) buffer;
12  SEGMENT* last = (SEGMENT*) (((uint8_t*) buffer) + size - SIZE_OF_CTRL);
13 
14  mBeginning->prev = 0;
15  mBeginning->next = last;
16  mBeginning->size = 0;
17 
18  last->prev = mBeginning;
19  last->next = 0;
20  last->size = 0;
21 
22  mFree = (uint8_t*) last - (uint8_t*) mBeginning - SIZE_OF_CTRL;
23  mTotalSize = mFree;
24  mBlockCount = 0;
25 }
26 
27 LibDmem::~LibDmem() {
28 
29 }
30 
31 void* LibDmem::alloc(size_t size) {
32  SEGMENT * prev = 0;
33  size = ALIGN_TO_SIZE(size, 4);
34  size_t requiredSize = size + SIZE_OF_CTRL;
35  size_t smallestGap = SIZE_MAX;
36 
37  for (SEGMENT* iterator = mBeginning; iterator->next; iterator = iterator->next) {
38  size_t currentGap = (uint8_t*) iterator->next - (uint8_t*) iterator - iterator->size - SIZE_OF_CTRL;
39 
40  if (currentGap == requiredSize) {
41  prev = iterator;
42  break;
43  }
44  if (currentGap >= requiredSize) {
45  if (currentGap < smallestGap) {
46  prev = iterator;
47  smallestGap = currentGap;
48  }
49  }
50  }
51 
52  if (!prev) {
53  return 0;
54  }
55 
56  SEGMENT* seg = (SEGMENT*) (((uint8_t*) prev) + prev->size + SIZE_OF_CTRL);
57 
58  seg->prev = prev;
59  seg->next = prev->next;
60  seg->size = size;
61  seg->next->prev = seg;
62  prev->next = seg;
63  mBlockCount++;
64  mFree -= requiredSize;
65 
66  return ((uint8_t*) seg) + SIZE_OF_CTRL;
67 }
68 
69 void LibDmem::free(void* p) {
70  LIB_ASSERT((p != 0)&&(p > mBeginning) && (p < (((uint8_t*)mBeginning)+mTotalSize)));
71 
72  SEGMENT* seg = (SEGMENT*) (((uint8_t*) p) - SIZE_OF_CTRL);
73 
74  seg->prev->next = seg->next;
75  seg->next->prev = seg->prev;
76 
77  mBlockCount--;
78  mFree += seg->size + SIZE_OF_CTRL;
79  if (mFree > mTotalSize) {
80  __asm volatile("nop\n");
81  }
82 }
83 
84 void* LibDmem::resize(void* p, size_t size) {
85  LIB_ASSERT((p != 0)&&(p > mBeginning) && (p < (((uint8_t*)mBeginning)+mTotalSize)));
86 
87  if (size == 0) {
88  free(p);
89  return 0;
90  }
91  if (p == 0) {
92  return alloc(size);
93  }
94 
95  size = ALIGN_TO_SIZE(size, 4);
96  SEGMENT* seg = (SEGMENT*) (((uint8_t*) p) - SIZE_OF_CTRL);
97 
98  size_t available = (uint8_t*) seg->next - (uint8_t*) seg - SIZE_OF_CTRL;
99  if (size <= available) {
100  mFree += seg->size - size;
101  seg->size = size;
102  return p;
103  }
104 
105  //Try to allocate a new segment
106  void* newSeg = alloc(size);
107  if (!newSeg) {
108  free(p);
109  return 0;
110  }
111  memcpy(newSeg, p, seg->size);
112  free(p);
113  return newSeg;
114 }
115 
116 void* LibDmem::resizeLeft(void* p, size_t left) {
117  LIB_ASSERT((p != 0)&&(p > mBeginning) && (p < (((uint8_t*)mBeginning)+mTotalSize)));
118  LIB_ASSERT((left%4)==0);
119 
120  SEGMENT* oldSeg = (SEGMENT*) (((uint8_t*) p) - SIZE_OF_CTRL);
121 
122  if (left > oldSeg->size) {
123  return 0;
124  }
125 
126  SEGMENT* newSeg = (SEGMENT*) (((uint8_t*) oldSeg) + left);
127 
128  SEGMENT* prev = oldSeg->prev;
129  SEGMENT* next = oldSeg->next;
130  size_t size = oldSeg->size - left;
131 
132  newSeg->prev = prev;
133  newSeg->next = next;
134  newSeg->size = size;
135 
136  if (prev) {
137  prev->next = newSeg;
138  }
139  if (next) {
140  next->prev = newSeg;
141  }
142 
143  mFree += left;
144  return ((uint8_t*) newSeg) + SIZE_OF_CTRL;
145 }
146 
147 size_t LibDmem::getTotalMemory() {
148  return mTotalSize;
149 }
150 
151 size_t LibDmem::getFreeMemory() {
152  return mFree;
153 }
154 
155 unsigned int LibDmem::getBlockCount() {
156  return mBlockCount;
157 }
158