1 |
27 |
unneback |
#ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_INL
|
2 |
|
|
#define CYGONCE_MEMALLOC_SEPMETAIMPL_INL
|
3 |
|
|
|
4 |
|
|
//==========================================================================
|
5 |
|
|
//
|
6 |
|
|
// sepmetaimpl.inl
|
7 |
|
|
//
|
8 |
|
|
// Variable block memory pool with separate metadata class declarations
|
9 |
|
|
//
|
10 |
|
|
//==========================================================================
|
11 |
|
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
12 |
|
|
// -------------------------------------------
|
13 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
14 |
|
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
15 |
|
|
//
|
16 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
17 |
|
|
// the terms of the GNU General Public License as published by the Free
|
18 |
|
|
// Software Foundation; either version 2 or (at your option) any later version.
|
19 |
|
|
//
|
20 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
21 |
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
22 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
23 |
|
|
// for more details.
|
24 |
|
|
//
|
25 |
|
|
// You should have received a copy of the GNU General Public License along
|
26 |
|
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
27 |
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
28 |
|
|
//
|
29 |
|
|
// As a special exception, if other files instantiate templates or use macros
|
30 |
|
|
// or inline functions from this file, or you compile this file and link it
|
31 |
|
|
// with other works to produce a work based on this file, this file does not
|
32 |
|
|
// by itself cause the resulting work to be covered by the GNU General Public
|
33 |
|
|
// License. However the source code for this file must still be made available
|
34 |
|
|
// in accordance with section (3) of the GNU General Public License.
|
35 |
|
|
//
|
36 |
|
|
// This exception does not invalidate any other reasons why a work based on
|
37 |
|
|
// this file might be covered by the GNU General Public License.
|
38 |
|
|
//
|
39 |
|
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
40 |
|
|
// at http://sources.redhat.com/ecos/ecos-license/
|
41 |
|
|
// -------------------------------------------
|
42 |
|
|
//####ECOSGPLCOPYRIGHTEND####
|
43 |
|
|
//==========================================================================
|
44 |
|
|
//#####DESCRIPTIONBEGIN####
|
45 |
|
|
//
|
46 |
|
|
// Author(s): jlarmour
|
47 |
|
|
// Contributors: hmt
|
48 |
|
|
// Date: 2001-06-28
|
49 |
|
|
// Purpose: Define Sepmetaimpl class interface
|
50 |
|
|
// Description: Inline class for constructing a variable block allocator
|
51 |
|
|
// with separate metadata.
|
52 |
|
|
// Usage: #include
|
53 |
|
|
//
|
54 |
|
|
//
|
55 |
|
|
//####DESCRIPTIONEND####
|
56 |
|
|
//
|
57 |
|
|
//==========================================================================
|
58 |
|
|
|
59 |
|
|
#include
|
60 |
|
|
#ifdef CYGPKG_ISOINFRA
|
61 |
|
|
# include
|
62 |
|
|
#endif
|
63 |
|
|
#include
|
64 |
|
|
#include
|
65 |
|
|
|
66 |
|
|
#include // assertion support
|
67 |
|
|
#include // tracing support
|
68 |
|
|
|
69 |
|
|
// Simple allocator
|
70 |
|
|
|
71 |
|
|
// The memory block lists are doubly linked lists. One for all alloced
|
72 |
|
|
// blocks, one for all free blocks. There's also a list of unused
|
73 |
|
|
// metadata from the metadata pool. The head of the
|
74 |
|
|
// list has the same structure but its memnext/memprev fields are zero.
|
75 |
|
|
// Always having at least one item on the list simplifies the alloc and
|
76 |
|
|
// free code.
|
77 |
|
|
#ifdef CYGINT_ISO_STRING_MEMFUNCS
|
78 |
|
|
# include
|
79 |
|
|
#endif
|
80 |
|
|
|
81 |
|
|
inline void
|
82 |
|
|
Cyg_Mempool_Sepmeta_Implementation::copy_data( cyg_uint8 *dst,
|
83 |
|
|
cyg_uint8 *src,
|
84 |
|
|
cyg_int32 nbytes )
|
85 |
|
|
{
|
86 |
|
|
#ifdef CYGINT_ISO_STRING_MEMFUNCS
|
87 |
|
|
memmove( dst, src, nbytes );
|
88 |
|
|
#else
|
89 |
|
|
if ((src < dst) && (dst < (src + nbytes))) {
|
90 |
|
|
// Have to copy backwards
|
91 |
|
|
src += nbytes;
|
92 |
|
|
dst += nbytes;
|
93 |
|
|
while (nbytes--) {
|
94 |
|
|
*--dst = *--src;
|
95 |
|
|
}
|
96 |
|
|
} else {
|
97 |
|
|
while (nbytes--) {
|
98 |
|
|
*dst++ = *src++;
|
99 |
|
|
}
|
100 |
|
|
}
|
101 |
|
|
#endif
|
102 |
|
|
}
|
103 |
|
|
|
104 |
|
|
inline cyg_uint8 *
|
105 |
|
|
Cyg_Mempool_Sepmeta_Implementation::alignup( cyg_uint8 *addr )
|
106 |
|
|
{
|
107 |
|
|
return (cyg_uint8 *)((cyg_int32)(addr + alignment-1) & -alignment);
|
108 |
|
|
}
|
109 |
|
|
|
110 |
|
|
inline cyg_uint8 *
|
111 |
|
|
Cyg_Mempool_Sepmeta_Implementation::aligndown( cyg_uint8 *addr )
|
112 |
|
|
{
|
113 |
|
|
return (cyg_uint8 *)((cyg_int32)addr & -alignment);
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
inline cyg_uint8 *
|
117 |
|
|
Cyg_Mempool_Sepmeta_Implementation::alignmetaup( cyg_uint8 *addr )
|
118 |
|
|
{
|
119 |
|
|
const size_t memdqalign = __alignof__ (struct memdq);
|
120 |
|
|
return (cyg_uint8 *)((cyg_int32)(addr + memdqalign-1) & -memdqalign);
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
inline cyg_uint8 *
|
124 |
|
|
Cyg_Mempool_Sepmeta_Implementation::alignmetadown( cyg_uint8 *addr )
|
125 |
|
|
{
|
126 |
|
|
const size_t memdqalign = __alignof__ (struct memdq);
|
127 |
|
|
return (cyg_uint8 *)((cyg_int32)addr & -memdqalign);
|
128 |
|
|
}
|
129 |
|
|
|
130 |
|
|
// return the alloced dq at mem
|
131 |
|
|
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
|
132 |
|
|
Cyg_Mempool_Sepmeta_Implementation::find_alloced_dq( cyg_uint8 *mem )
|
133 |
|
|
{
|
134 |
|
|
struct memdq *dq=allocedhead.next;
|
135 |
|
|
|
136 |
|
|
while (dq->mem != mem ) {
|
137 |
|
|
CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
|
138 |
|
|
CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq");
|
139 |
|
|
if (dq->next == &memend) // address not found!
|
140 |
|
|
return NULL;
|
141 |
|
|
dq = dq->next;
|
142 |
|
|
}
|
143 |
|
|
return dq;
|
144 |
|
|
}
|
145 |
|
|
|
146 |
|
|
// returns a free dq of at least size, or NULL if none
|
147 |
|
|
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
|
148 |
|
|
Cyg_Mempool_Sepmeta_Implementation::find_free_dq( cyg_int32 size )
|
149 |
|
|
{
|
150 |
|
|
struct memdq *dq = freehead.next;
|
151 |
|
|
|
152 |
|
|
while ( (dq->memnext->mem - dq->mem) < size ) {
|
153 |
|
|
CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
|
154 |
|
|
CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq");
|
155 |
|
|
if (dq->next == &freehead) { // reached end of list
|
156 |
|
|
return NULL;
|
157 |
|
|
}
|
158 |
|
|
dq = dq->next; // next on free list
|
159 |
|
|
}
|
160 |
|
|
return dq;
|
161 |
|
|
}
|
162 |
|
|
|
163 |
|
|
// returns the free dq following mem
|
164 |
|
|
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
|
165 |
|
|
Cyg_Mempool_Sepmeta_Implementation::find_free_dq_slot( cyg_uint8 *mem )
|
166 |
|
|
{
|
167 |
|
|
struct memdq *dq;
|
168 |
|
|
for (dq = freehead.next; dq->mem < mem; dq = dq->next) {
|
169 |
|
|
if ( dq == &freehead ) // wrapped round
|
170 |
|
|
break;
|
171 |
|
|
}
|
172 |
|
|
return dq;
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
inline void
|
176 |
|
|
Cyg_Mempool_Sepmeta_Implementation::check_free_memdq( struct memdq *dq )
|
177 |
|
|
{
|
178 |
|
|
if (dq == &freehead)
|
179 |
|
|
return;
|
180 |
|
|
CYG_ASSERT(dq->memnext->memprev == dq, "corrupted free dq #1");
|
181 |
|
|
CYG_ASSERT(dq->next->prev == dq, "corrupted free dq #2");
|
182 |
|
|
CYG_ASSERT(dq->memprev->memnext == dq, "corrupted free dq #3");
|
183 |
|
|
CYG_ASSERT(dq->prev->next == dq, "corrupted free dq #4");
|
184 |
|
|
CYG_ASSERT(dq->memnext->mem > dq->mem, "free dq mem not sorted #1");
|
185 |
|
|
if (dq->memprev != &memend)
|
186 |
|
|
CYG_ASSERT(dq->memprev->mem < dq->mem, "free dq mem not sorted #2");
|
187 |
|
|
}
|
188 |
|
|
|
189 |
|
|
inline void
|
190 |
|
|
Cyg_Mempool_Sepmeta_Implementation::check_alloced_memdq( struct memdq *dq )
|
191 |
|
|
{
|
192 |
|
|
CYG_ASSERT(dq->memnext->memprev == dq, "corrupted alloced dq #1");
|
193 |
|
|
CYG_ASSERT(dq->next->prev == dq, "corrupted alloced dq #2");
|
194 |
|
|
CYG_ASSERT(dq->memprev->memnext == dq, "corrupted alloced dq #3");
|
195 |
|
|
CYG_ASSERT(dq->prev->next == dq, "corrupted alloced dq #4");
|
196 |
|
|
if (dq != &memend)
|
197 |
|
|
CYG_ASSERT(dq->memnext->mem > dq->mem, "alloced dq mem not sorted #1");
|
198 |
|
|
if (dq->memprev != &memhead)
|
199 |
|
|
CYG_ASSERT(dq->memprev->mem < dq->mem, "alloced dq mem not sorted #2");
|
200 |
|
|
}
|
201 |
|
|
|
202 |
|
|
// -------------------------------------------------------------------------
|
203 |
|
|
|
204 |
|
|
inline void
|
205 |
|
|
Cyg_Mempool_Sepmeta_Implementation::insert_free_block( struct memdq *dq )
|
206 |
|
|
{
|
207 |
|
|
// scan for correct slot in the sorted free list
|
208 |
|
|
struct memdq *fdq = find_free_dq_slot( dq->mem );
|
209 |
|
|
|
210 |
|
|
CYG_ASSERT(fdq != &freehead ? fdq->mem > dq->mem : 1,
|
211 |
|
|
"Block address is already in freelist");
|
212 |
|
|
|
213 |
|
|
check_free_memdq(fdq);
|
214 |
|
|
|
215 |
|
|
if (dq->memnext == fdq) {
|
216 |
|
|
// we can coalesce these two together
|
217 |
|
|
// adjust fdq's mem address backwards to include dq
|
218 |
|
|
fdq->mem = dq->mem;
|
219 |
|
|
// and remove dq
|
220 |
|
|
fdq->memprev = dq->memprev;
|
221 |
|
|
fdq->memprev->memnext = fdq;
|
222 |
|
|
// Don't need to adjust fdq's next/prev links as it stays in the
|
223 |
|
|
// same place in the free list
|
224 |
|
|
|
225 |
|
|
// dq is now redundant so return to metadata free list
|
226 |
|
|
dq->next = freemetahead;
|
227 |
|
|
freemetahead = dq;
|
228 |
|
|
|
229 |
|
|
// reset dq
|
230 |
|
|
dq = fdq;
|
231 |
|
|
} else {
|
232 |
|
|
// insert behind fdq
|
233 |
|
|
dq->next = fdq;
|
234 |
|
|
dq->prev = fdq->prev;
|
235 |
|
|
fdq->prev = dq;
|
236 |
|
|
dq->prev->next = dq;
|
237 |
|
|
}
|
238 |
|
|
|
239 |
|
|
check_free_memdq(dq);
|
240 |
|
|
|
241 |
|
|
// maybe also coalesce backwards
|
242 |
|
|
if (dq->memprev == dq->prev) {
|
243 |
|
|
// adjust dq's mem address backwards to include dq->prev
|
244 |
|
|
dq->mem = dq->prev->mem;
|
245 |
|
|
|
246 |
|
|
// return dq->prev to metadata free list
|
247 |
|
|
dq->prev->next = freemetahead;
|
248 |
|
|
freemetahead = dq->prev;
|
249 |
|
|
|
250 |
|
|
// and remove dq->prev from mem list
|
251 |
|
|
dq->memprev = dq->prev->memprev;
|
252 |
|
|
dq->memprev->memnext = dq;
|
253 |
|
|
// and free list
|
254 |
|
|
dq->prev = dq->prev->prev;
|
255 |
|
|
dq->prev->next = dq;
|
256 |
|
|
|
257 |
|
|
check_free_memdq(dq);
|
258 |
|
|
}
|
259 |
|
|
}
|
260 |
|
|
|
261 |
|
|
// -------------------------------------------------------------------------
|
262 |
|
|
#include
|
263 |
|
|
inline
|
264 |
|
|
Cyg_Mempool_Sepmeta_Implementation::Cyg_Mempool_Sepmeta_Implementation(
|
265 |
|
|
cyg_uint8 *base,
|
266 |
|
|
cyg_int32 size,
|
267 |
|
|
CYG_ADDRWORD consargs)
|
268 |
|
|
{
|
269 |
|
|
CYG_REPORT_FUNCTION();
|
270 |
|
|
struct constructorargs *args = (struct constructorargs *)consargs;
|
271 |
|
|
CYG_CHECK_DATA_PTRC( args );
|
272 |
|
|
|
273 |
|
|
alignment = args->alignment;
|
274 |
|
|
|
275 |
|
|
CYG_ASSERT( alignment > 0, "Bad alignment" );
|
276 |
|
|
CYG_ASSERT( 0!=alignment, "alignment is zero" );
|
277 |
|
|
CYG_ASSERT( 0==(alignment & alignment-1), "alignment not a power of 2" );
|
278 |
|
|
|
279 |
|
|
obase=base;
|
280 |
|
|
osize=size;
|
281 |
|
|
metabase = args->metabase;
|
282 |
|
|
metasize = args->metasize;
|
283 |
|
|
|
284 |
|
|
// bottom is set to the lowest available address given the alignment.
|
285 |
|
|
bottom = alignup( base );
|
286 |
|
|
cyg_uint8 *metabottom = alignmetaup( metabase );
|
287 |
|
|
|
288 |
|
|
// because we split free blocks by allocating memory from the end, not
|
289 |
|
|
// the beginning, then to preserve alignment, the *top* must also be
|
290 |
|
|
// aligned
|
291 |
|
|
top = aligndown( base+size );
|
292 |
|
|
cyg_uint8 *metatop = metabottom +
|
293 |
|
|
sizeof(struct memdq)*(metasize/sizeof(struct memdq));
|
294 |
|
|
|
295 |
|
|
CYG_ASSERT( top > bottom , "heap too small" );
|
296 |
|
|
CYG_ASSERT( top <= (base+size), "top too large" );
|
297 |
|
|
CYG_ASSERT( (((cyg_int32)(top)) & alignment-1)==0,
|
298 |
|
|
"top badly aligned" );
|
299 |
|
|
CYG_ASSERT( (((cyg_int32)(bottom)) & alignment-1)==0,
|
300 |
|
|
"bottom badly aligned" );
|
301 |
|
|
|
302 |
|
|
CYG_ASSERT( metatop > metabottom , "meta space too small" );
|
303 |
|
|
CYG_ASSERT( metatop <= (metabase+metasize), "metatop too large" );
|
304 |
|
|
|
305 |
|
|
// Initialize list of unused metadata blocks. Only need to do next
|
306 |
|
|
// pointers - can ignore prev and size
|
307 |
|
|
struct memdq *fq = freemetahead = (struct memdq *)metabottom;
|
308 |
|
|
|
309 |
|
|
while ((cyg_uint8 *)fq < metatop) {
|
310 |
|
|
fq->next = fq+1;
|
311 |
|
|
fq++;
|
312 |
|
|
}
|
313 |
|
|
|
314 |
|
|
CYG_ASSERT((cyg_uint8 *)fq == metatop, "traversed metadata not aligned");
|
315 |
|
|
|
316 |
|
|
// set final pointer to NULL;
|
317 |
|
|
--fq; fq->next = NULL;
|
318 |
|
|
|
319 |
|
|
// initialize the free list. memhead is the initial free block occupying
|
320 |
|
|
// all of free memory.
|
321 |
|
|
memhead.next = memhead.prev = &freehead;
|
322 |
|
|
// The mem list is circular for consistency.
|
323 |
|
|
memhead.memprev = memhead.memnext = &memend;
|
324 |
|
|
memhead.mem = bottom;
|
325 |
|
|
|
326 |
|
|
// initialize block that indicates end of memory. This pretends to
|
327 |
|
|
// be an allocated block
|
328 |
|
|
memend.next = memend.prev = &allocedhead;
|
329 |
|
|
memend.memnext = memend.memprev = &memhead;
|
330 |
|
|
memend.mem = top;
|
331 |
|
|
|
332 |
|
|
// initialize alloced list memdq. memend pretends to be allocated memory
|
333 |
|
|
// at the end
|
334 |
|
|
allocedhead.next = allocedhead.prev = &memend;
|
335 |
|
|
freehead.next = freehead.prev = &memhead;
|
336 |
|
|
// Since allocedhead and freehead are placeholders, not real blocks,
|
337 |
|
|
// assign addresses which can't match list searches
|
338 |
|
|
allocedhead.memnext = allocedhead.memprev = NULL;
|
339 |
|
|
freehead.memnext = freehead.memprev = NULL;
|
340 |
|
|
freehead.mem = allocedhead.mem = NULL;
|
341 |
|
|
|
342 |
|
|
freemem = top - bottom;
|
343 |
|
|
}
|
344 |
|
|
|
345 |
|
|
// -------------------------------------------------------------------------
|
346 |
|
|
|
347 |
|
|
inline
|
348 |
|
|
Cyg_Mempool_Sepmeta_Implementation::~Cyg_Mempool_Sepmeta_Implementation()
|
349 |
|
|
{
|
350 |
|
|
}
|
351 |
|
|
|
352 |
|
|
// -------------------------------------------------------------------------
|
353 |
|
|
// allocation is mostly simple
|
354 |
|
|
// First we look down the free list for a large enough block
|
355 |
|
|
// If we find a block the right size, we unlink the block from
|
356 |
|
|
// the free list and return a pointer to it.
|
357 |
|
|
// If we find a larger block, we chop a piece off the end
|
358 |
|
|
// and return that
|
359 |
|
|
// Otherwise we reach the end of the list and return NULL
|
360 |
|
|
|
361 |
|
|
inline cyg_uint8 *
|
362 |
|
|
Cyg_Mempool_Sepmeta_Implementation::try_alloc( cyg_int32 size )
|
363 |
|
|
{
|
364 |
|
|
struct memdq *alloced;
|
365 |
|
|
|
366 |
|
|
CYG_REPORT_FUNCTION();
|
367 |
|
|
|
368 |
|
|
// Allow uninitialised (zero sized) heaps because they could exist as a
|
369 |
|
|
// quirk of the MLT setup where a dynamically sized heap is at the top of
|
370 |
|
|
// memory.
|
371 |
|
|
if (NULL == bottom || NULL==metabase)
|
372 |
|
|
return NULL;
|
373 |
|
|
|
374 |
|
|
size = (size + alignment - 1) & -alignment;
|
375 |
|
|
|
376 |
|
|
struct memdq *dq = find_free_dq( size );
|
377 |
|
|
if (NULL == dq)
|
378 |
|
|
return NULL;
|
379 |
|
|
|
380 |
|
|
cyg_int32 dqsize = dq->memnext->mem - dq->mem;
|
381 |
|
|
|
382 |
|
|
if( size == dqsize ) {
|
383 |
|
|
// exact fit -- unlink from free list
|
384 |
|
|
dq->prev->next = dq->next;
|
385 |
|
|
dq->next->prev = dq->prev;
|
386 |
|
|
|
387 |
|
|
// set up this block for insertion into alloced list
|
388 |
|
|
dq->next = dq->memnext; // since dq was free, dq->memnext must
|
389 |
|
|
// be allocated otherwise it would have
|
390 |
|
|
// been coalesced
|
391 |
|
|
dq->prev = dq->next->prev;
|
392 |
|
|
|
393 |
|
|
alloced = dq;
|
394 |
|
|
} else {
|
395 |
|
|
|
396 |
|
|
CYG_ASSERT( dqsize > size, "block found is too small");
|
397 |
|
|
|
398 |
|
|
// Split into two memdq's, returning the second one
|
399 |
|
|
|
400 |
|
|
// first get a memdq
|
401 |
|
|
|
402 |
|
|
if ( NULL == freemetahead ) // out of metadata.
|
403 |
|
|
return NULL;
|
404 |
|
|
|
405 |
|
|
// FIXME: since we don't search all the way for an exact fit
|
406 |
|
|
// first we may be able to find an exact fit later and therefore
|
407 |
|
|
// not need more metadata. We don't do this yet though.
|
408 |
|
|
|
409 |
|
|
alloced = freemetahead;
|
410 |
|
|
freemetahead = alloced->next;
|
411 |
|
|
|
412 |
|
|
// now set its values
|
413 |
|
|
alloced->memnext = dq->memnext;
|
414 |
|
|
alloced->next = dq->memnext; // since dq was free, dq->memnext must
|
415 |
|
|
// be allocated otherwise it would have
|
416 |
|
|
// been coalesced
|
417 |
|
|
alloced->memprev = dq;
|
418 |
|
|
alloced->prev = alloced->next->prev;
|
419 |
|
|
|
420 |
|
|
alloced->mem = alloced->next->mem - size;
|
421 |
|
|
|
422 |
|
|
// now set up dq (the portion that remains a free block)
|
423 |
|
|
// dq->next and dq->prev are unchanged as we still end up pointing
|
424 |
|
|
// at the same adjacent free blocks
|
425 |
|
|
// dq->memprev obviously doesn't change
|
426 |
|
|
|
427 |
|
|
dq->memnext = alloced;
|
428 |
|
|
|
429 |
|
|
// finish inserting into memory block list
|
430 |
|
|
alloced->memnext->memprev = alloced;
|
431 |
|
|
alloced->next->prev = alloced->prev->next = alloced;
|
432 |
|
|
|
433 |
|
|
check_free_memdq(dq);
|
434 |
|
|
}
|
435 |
|
|
|
436 |
|
|
CYG_ASSERT( bottom <= alloced->mem && alloced->mem <= top,
|
437 |
|
|
"alloced outside pool" );
|
438 |
|
|
|
439 |
|
|
// Insert block into alloced list.
|
440 |
|
|
alloced->next->prev = alloced->prev->next = alloced;
|
441 |
|
|
|
442 |
|
|
check_alloced_memdq(alloced);
|
443 |
|
|
|
444 |
|
|
freemem -=size;
|
445 |
|
|
|
446 |
|
|
CYG_ASSERT( ((CYG_ADDRESS)alloced->mem & (alignment-1)) == 0,
|
447 |
|
|
"returned memory not aligned" );
|
448 |
|
|
return alloced->mem;
|
449 |
|
|
}
|
450 |
|
|
|
451 |
|
|
// -------------------------------------------------------------------------
|
452 |
|
|
// resize existing allocation, if oldsize is non-NULL, previous
|
453 |
|
|
// allocation size is placed into it. If previous size not available,
|
454 |
|
|
// it is set to 0. NB previous allocation size may have been rounded up.
|
455 |
|
|
// Occasionally the allocation can be adjusted *backwards* as well as,
|
456 |
|
|
// or instead of forwards, therefore the address of the resized
|
457 |
|
|
// allocation is returned, or NULL if no resizing was possible.
|
458 |
|
|
// Note that this differs from ::realloc() in that no attempt is
|
459 |
|
|
// made to call malloc() if resizing is not possible - that is left
|
460 |
|
|
// to higher layers. The data is copied from old to new though.
|
461 |
|
|
// The effects of alloc_ptr==NULL or newsize==0 are undefined
|
462 |
|
|
|
463 |
|
|
inline cyg_uint8 *
|
464 |
|
|
Cyg_Mempool_Sepmeta_Implementation::resize_alloc( cyg_uint8 *alloc_ptr,
|
465 |
|
|
cyg_int32 newsize,
|
466 |
|
|
cyg_int32 *oldsize )
|
467 |
|
|
{
|
468 |
|
|
cyg_int32 currsize, origsize;
|
469 |
|
|
|
470 |
|
|
CYG_REPORT_FUNCTION();
|
471 |
|
|
|
472 |
|
|
CYG_CHECK_DATA_PTRC( alloc_ptr );
|
473 |
|
|
if ( NULL != oldsize )
|
474 |
|
|
CYG_CHECK_DATA_PTRC( oldsize );
|
475 |
|
|
|
476 |
|
|
CYG_ASSERT( (bottom <= alloc_ptr) && (alloc_ptr <= top),
|
477 |
|
|
"alloc_ptr outside pool" );
|
478 |
|
|
|
479 |
|
|
struct memdq *dq=find_alloced_dq( alloc_ptr );
|
480 |
|
|
CYG_ASSERT( dq != NULL, "passed address not previously alloced");
|
481 |
|
|
|
482 |
|
|
currsize = origsize = dq->memnext->mem - dq->mem;
|
483 |
|
|
if ( NULL != oldsize )
|
484 |
|
|
*oldsize = currsize;
|
485 |
|
|
|
486 |
|
|
if ( newsize > currsize ) {
|
487 |
|
|
cyg_int32 nextmemsize=0, prevmemsize=0;
|
488 |
|
|
|
489 |
|
|
// see if we can increase the allocation size. Don't change anything
|
490 |
|
|
// so we don't have to undo it later if it wouldn't fit
|
491 |
|
|
if ( dq->next != dq->memnext ) { // if not equal, memnext must
|
492 |
|
|
// be on free list
|
493 |
|
|
nextmemsize = dq->memnext->memnext->mem - dq->memnext->mem;
|
494 |
|
|
}
|
495 |
|
|
if ( dq->prev != dq->memprev) { // ditto
|
496 |
|
|
prevmemsize = dq->mem - dq->memprev->mem;
|
497 |
|
|
}
|
498 |
|
|
if (nextmemsize + prevmemsize + currsize < newsize)
|
499 |
|
|
return NULL; // can't fit it
|
500 |
|
|
|
501 |
|
|
// expand forwards
|
502 |
|
|
if ( nextmemsize != 0 ) {
|
503 |
|
|
if (nextmemsize <= (newsize - currsize)) { // taking all of it
|
504 |
|
|
struct memdq *fblk = dq->memnext;
|
505 |
|
|
|
506 |
|
|
// fix up mem list ptrs
|
507 |
|
|
dq->memnext = fblk->memnext;
|
508 |
|
|
dq->memnext->memprev=dq;
|
509 |
|
|
// fix up free list ptrs
|
510 |
|
|
fblk->next->prev = fblk->prev;
|
511 |
|
|
fblk->prev->next = fblk->next;
|
512 |
|
|
|
513 |
|
|
// return to meta list
|
514 |
|
|
fblk->next = freemetahead;
|
515 |
|
|
freemetahead = fblk->next;
|
516 |
|
|
currsize += nextmemsize;
|
517 |
|
|
} else { // only needs some
|
518 |
|
|
dq->memnext->mem += (newsize - currsize);
|
519 |
|
|
currsize = newsize;
|
520 |
|
|
}
|
521 |
|
|
}
|
522 |
|
|
|
523 |
|
|
// expand backwards
|
524 |
|
|
if ( currsize < newsize && prevmemsize != 0 ) {
|
525 |
|
|
cyg_uint8 *oldmem = dq->mem;
|
526 |
|
|
|
527 |
|
|
CYG_ASSERT( prevmemsize >= newsize - currsize,
|
528 |
|
|
"miscalculated expansion" );
|
529 |
|
|
if (prevmemsize == (newsize - currsize)) { // taking all of it
|
530 |
|
|
struct memdq *fblk = dq->memprev;
|
531 |
|
|
|
532 |
|
|
// fix up mem list ptrs
|
533 |
|
|
dq->memprev = fblk->memprev;
|
534 |
|
|
dq->memprev->memnext=dq;
|
535 |
|
|
dq->mem = fblk->mem;
|
536 |
|
|
// fix up free list ptrs
|
537 |
|
|
fblk->next->prev = fblk->prev;
|
538 |
|
|
fblk->prev->next = fblk->next;
|
539 |
|
|
|
540 |
|
|
// return to meta list
|
541 |
|
|
fblk->next = freemetahead;
|
542 |
|
|
freemetahead = fblk->next;
|
543 |
|
|
} else { // only needs some
|
544 |
|
|
dq->mem -= (newsize - currsize);
|
545 |
|
|
}
|
546 |
|
|
|
547 |
|
|
// move data into place
|
548 |
|
|
copy_data( dq->mem, oldmem, origsize );
|
549 |
|
|
}
|
550 |
|
|
}
|
551 |
|
|
|
552 |
|
|
if (newsize < currsize) {
|
553 |
|
|
// shrink allocation
|
554 |
|
|
|
555 |
|
|
// easy if the next block is already a free block
|
556 |
|
|
if ( dq->memnext != dq->next ) {
|
557 |
|
|
dq->memnext->mem -= currsize - newsize;
|
558 |
|
|
CYG_ASSERT( dq->memnext->mem > dq->mem,
|
559 |
|
|
"moving next block back corruption" );
|
560 |
|
|
} else {
|
561 |
|
|
// if its already allocated we need to create a new free list
|
562 |
|
|
// entry
|
563 |
|
|
if (NULL == freemetahead)
|
564 |
|
|
return NULL; // can't do it
|
565 |
|
|
|
566 |
|
|
struct memdq *fdq = freemetahead;
|
567 |
|
|
freemetahead = fdq->next;
|
568 |
|
|
|
569 |
|
|
fdq->memprev = dq;
|
570 |
|
|
fdq->memnext = dq->memnext;
|
571 |
|
|
fdq->mem = dq->mem + newsize;
|
572 |
|
|
|
573 |
|
|
insert_free_block( fdq );
|
574 |
|
|
}
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
freemem += origsize - newsize;
|
578 |
|
|
|
579 |
|
|
return dq->mem;
|
580 |
|
|
} // resize_alloc()
|
581 |
|
|
|
582 |
|
|
|
583 |
|
|
// -------------------------------------------------------------------------
|
584 |
|
|
// When no coalescing is done, free is simply a matter of using the
|
585 |
|
|
// freed memory as an element of the free list linking it in at the
|
586 |
|
|
// start. When coalescing, the free list is sorted
|
587 |
|
|
|
588 |
|
|
inline cyg_bool
|
589 |
|
|
Cyg_Mempool_Sepmeta_Implementation::free( cyg_uint8 *p, cyg_int32 size )
|
590 |
|
|
{
|
591 |
|
|
CYG_REPORT_FUNCTION();
|
592 |
|
|
|
593 |
|
|
CYG_CHECK_DATA_PTRC( p );
|
594 |
|
|
|
595 |
|
|
if (!((bottom <= p) && (p <= top)))
|
596 |
|
|
return false;
|
597 |
|
|
|
598 |
|
|
struct memdq *dq = find_alloced_dq( p );
|
599 |
|
|
if (NULL == dq)
|
600 |
|
|
return false;
|
601 |
|
|
|
602 |
|
|
if (0 == size)
|
603 |
|
|
size = dq->memnext->mem - dq->mem;
|
604 |
|
|
else {
|
605 |
|
|
size = (size + alignment - 1) & -alignment;
|
606 |
|
|
if( (dq->memnext->mem - dq->mem) != size )
|
607 |
|
|
return false;
|
608 |
|
|
}
|
609 |
|
|
|
610 |
|
|
check_alloced_memdq( dq );
|
611 |
|
|
|
612 |
|
|
// Remove dq from alloced list
|
613 |
|
|
dq->prev->next = dq->next;
|
614 |
|
|
dq->next->prev = dq->prev;
|
615 |
|
|
|
616 |
|
|
insert_free_block( dq );
|
617 |
|
|
|
618 |
|
|
freemem += size;
|
619 |
|
|
|
620 |
|
|
return true;
|
621 |
|
|
}
|
622 |
|
|
|
623 |
|
|
// -------------------------------------------------------------------------
|
624 |
|
|
|
625 |
|
|
inline void
|
626 |
|
|
Cyg_Mempool_Sepmeta_Implementation::get_status(
|
627 |
|
|
cyg_mempool_status_flag_t flags,
|
628 |
|
|
Cyg_Mempool_Status &status )
|
629 |
|
|
{
|
630 |
|
|
CYG_REPORT_FUNCTION();
|
631 |
|
|
|
632 |
|
|
// as quick or quicker to just set it, rather than test flag first
|
633 |
|
|
status.arenabase = obase;
|
634 |
|
|
if ( 0 != (flags & CYG_MEMPOOL_STAT_ARENASIZE) )
|
635 |
|
|
status.arenasize = top - bottom;
|
636 |
|
|
if ( 0 != (flags & CYG_MEMPOOL_STAT_TOTALALLOCATED) )
|
637 |
|
|
status.totalallocated = (top-bottom) - freemem;
|
638 |
|
|
// as quick or quicker to just set it, rather than test flag first
|
639 |
|
|
status.totalfree = freemem;
|
640 |
|
|
if ( 0 != (flags & CYG_MEMPOOL_STAT_MAXFREE) ) {
|
641 |
|
|
struct memdq *dq = &freehead;
|
642 |
|
|
cyg_int32 mf = 0;
|
643 |
|
|
|
644 |
|
|
do {
|
645 |
|
|
CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
|
646 |
|
|
dq = dq->next;
|
647 |
|
|
if (dq == &freehead) // wrapped round
|
648 |
|
|
break;
|
649 |
|
|
if(dq->memnext->mem - dq->mem > mf)
|
650 |
|
|
mf = dq->memnext->mem - dq->mem;
|
651 |
|
|
} while(1);
|
652 |
|
|
status.maxfree = mf;
|
653 |
|
|
}
|
654 |
|
|
// as quick or quicker to just set it, rather than test flag first
|
655 |
|
|
status.origbase = obase;
|
656 |
|
|
// as quick or quicker to just set it, rather than test flag first
|
657 |
|
|
status.origsize = osize;
|
658 |
|
|
|
659 |
|
|
CYG_REPORT_RETURN();
|
660 |
|
|
|
661 |
|
|
} // get_status()
|
662 |
|
|
|
663 |
|
|
|
664 |
|
|
// -------------------------------------------------------------------------
|
665 |
|
|
#endif // ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_INL
|
666 |
|
|
// EOF sepmetaimpl.inl
|