OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [services/] [memalloc/] [common/] [current/] [include/] [mvarimpl.inl] - Blame information for rev 838

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#ifndef CYGONCE_MEMALLOC_MVARIMPL_INL
2
#define CYGONCE_MEMALLOC_MVARIMPL_INL
3
 
4
//==========================================================================
5
//
6
//      mvarimpl.inl
7
//
8
//      Memory pool with variable block 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 Free Software Foundation, 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
19
// version.
20
//
21
// eCos is distributed in the hope that it will be useful, but WITHOUT
22
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24
// for more details.
25
//
26
// You should have received a copy of the GNU General Public License
27
// along with eCos; if not, write to the Free Software Foundation, Inc.,
28
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
29
//
30
// As a special exception, if other files instantiate templates or use
31
// macros or inline functions from this file, or you compile this file
32
// and link it with other works to produce a work based on this file,
33
// this file does not by itself cause the resulting work to be covered by
34
// the GNU General Public License. However the source code for this file
35
// must still be made available in accordance with section (3) of the GNU
36
// General Public License v2.
37
//
38
// This exception does not invalidate any other reasons why a work based
39
// on this file might be covered by the GNU General Public License.
40
// -------------------------------------------
41
// ####ECOSGPLCOPYRIGHTEND####
42
//==========================================================================
43
//#####DESCRIPTIONBEGIN####
44
//
45
// Author(s):    hmt
46
// Contributors: jlarmour
47
// Date:         2000-06-12
48
// Purpose:      Define Mvarimpl class interface
49
// Description:  Inline class for constructing a variable block allocator
50
// Usage:        #include 
51
//
52
//
53
//####DESCRIPTIONEND####
54
//
55
//==========================================================================
56
 
57
#include 
58
#include 
59
 
60
#include            // assertion support
61
#include           // tracing support
62
 
63
// Simple allocator
64
 
65
// The free list is stored on a doubly linked list, each member of
66
// which is stored in the body of the free memory.  The head of the
67
// list has the same structure but its size field is zero.  This
68
// resides in the memory pool structure.  Always having at least one
69
// item on the list simplifies the alloc and free code.
70
 
71
//
72
inline cyg_int32
73
Cyg_Mempool_Variable_Implementation::roundup( cyg_int32 size )
74
{
75
 
76
    size += sizeof(struct memdq);
77
    size = (size + alignment - 1) & -alignment;
78
    return size;
79
}
80
 
81
inline struct Cyg_Mempool_Variable_Implementation::memdq *
82
Cyg_Mempool_Variable_Implementation::addr2memdq( cyg_uint8 *addr )
83
{
84
    struct memdq *dq;
85
    dq = (struct memdq *)(roundup((cyg_int32)addr) - sizeof(struct memdq));
86
    return dq;
87
}
88
 
89
inline struct Cyg_Mempool_Variable_Implementation::memdq *
90
Cyg_Mempool_Variable_Implementation::alloc2memdq( cyg_uint8 *addr )
91
{
92
    return (struct memdq *)(addr - sizeof(struct memdq));
93
}
94
 
95
inline cyg_uint8 *
96
Cyg_Mempool_Variable_Implementation::memdq2alloc( struct memdq *dq )
97
{
98
    return ((cyg_uint8 *)dq + sizeof(struct memdq));
99
}
100
 
101
// -------------------------------------------------------------------------
102
 
103
inline void
104
Cyg_Mempool_Variable_Implementation::insert_free_block( struct memdq *dq )
105
{
106
    struct memdq *hdq=&head;
107
 
108
    freemem += dq->size;
109
#ifdef CYGSEM_MEMALLOC_ALLOCATOR_VARIABLE_COALESCE
110
// For simple coalescing have the free list be sorted by memory base address
111
    struct memdq *idq;
112
 
113
    for (idq = hdq->next; idq != hdq; idq = idq->next) {
114
        if (idq > dq)
115
            break;
116
    }
117
    // we want to insert immediately before idq
118
    dq->next = idq;
119
    dq->prev = idq->prev;
120
    idq->prev = dq;
121
    dq->prev->next = dq;
122
 
123
    // Now do coalescing, but leave the head of the list alone.
124
    if (dq->next != hdq && (char *)dq + dq->size == (char *)dq->next) {
125
        dq->size += dq->next->size;
126
        dq->next = dq->next->next;
127
        dq->next->prev = dq;
128
    }
129
    if (dq->prev != hdq && (char *)dq->prev + dq->prev->size == (char *)dq) {
130
        dq->prev->size += dq->size;
131
        dq->prev->next = dq->next;
132
        dq->next->prev = dq->prev;
133
        dq = dq->prev;
134
    }
135
#else
136
    dq->prev = hdq;
137
    dq->next = hdq->next;
138
    hdq->next = dq;
139
    dq->next->prev=dq;
140
#endif
141
}
142
 
143
// -------------------------------------------------------------------------
144
 
145
inline
146
Cyg_Mempool_Variable_Implementation::Cyg_Mempool_Variable_Implementation(
147
        cyg_uint8 *base,
148
        cyg_int32 size,
149
        CYG_ADDRWORD align )
150
{
151
    CYG_REPORT_FUNCTION();
152
 
153
    CYG_ASSERT( align > 0, "Bad alignment" );
154
    CYG_ASSERT(0!=align ,"align is zero");
155
    CYG_ASSERT(0==(align & (align-1)),"align not a power of 2");
156
 
157
    if ((unsigned)size < sizeof(struct memdq)) {
158
        bottom = NULL;
159
        return;
160
    }
161
 
162
    obase=base;
163
    osize=size;
164
 
165
    alignment = align;
166
    while (alignment < (cyg_int32)sizeof(struct memdq))
167
        alignment += alignment;
168
    CYG_ASSERT(0==(alignment & (alignment-1)),"alignment not a power of 2");
169
 
170
    // the memdq for each allocation is always positioned immediately before
171
    // an aligned address, so that the allocation (i.e. what eventually gets
172
    // returned from alloc()) is at the correctly aligned address
173
    // Therefore bottom is set to the lowest available address given the size of
174
    // struct memdq and the alignment.
175
    bottom = (cyg_uint8 *)addr2memdq(base);
176
 
177
    // because we split free blocks by allocating memory from the end, not
178
    // the beginning, then to preserve alignment, the *top* must also be
179
    // aligned such that (top-bottom) is a multiple of the alignment
180
    top = (cyg_uint8 *)((cyg_int32)(base+size+sizeof(struct memdq)) & -alignment) -
181
        sizeof(struct memdq);
182
 
183
    CYG_ASSERT( top > bottom , "heap too small" );
184
    CYG_ASSERT( top <= (base+size), "top too large" );
185
    CYG_ASSERT( ((cyg_int32)(top+sizeof(struct memdq)) & (alignment-1))==0,
186
                "top badly aligned" );
187
 
188
    struct memdq *hdq = &head, *dq = (struct memdq *)bottom;
189
 
190
    CYG_ASSERT( ((cyg_int32)memdq2alloc(dq) & (alignment-1))==0,
191
                 "bottom badly aligned" );
192
 
193
    hdq->prev = hdq->next = dq;
194
    hdq->size = 0;
195
    dq->prev = dq->next = hdq;
196
 
197
    freemem = dq->size = top - bottom;
198
}
199
 
200
// -------------------------------------------------------------------------
201
 
202
inline
203
Cyg_Mempool_Variable_Implementation::~Cyg_Mempool_Variable_Implementation()
204
{
205
}
206
 
207
// -------------------------------------------------------------------------
208
// allocation is simple
209
// First we look down the free list for a large enough block
210
// If we find a block the right size, we unlink the block from
211
//    the free list and return a pointer to it.
212
// If we find a larger block, we chop a piece off the end
213
//    and return that
214
// Otherwise we will eventually get back to the head of the list
215
//    and return NULL
216
inline cyg_uint8 *
217
Cyg_Mempool_Variable_Implementation::try_alloc( cyg_int32 size )
218
{
219
    struct memdq *dq = &head;
220
    cyg_uint8 *alloced;
221
 
222
    CYG_REPORT_FUNCTION();
223
 
224
    //  Allow uninitialised (zero sized) heaps because they could exist as a
225
    //  quirk of the MLT setup where a dynamically sized heap is at the top of
226
    //  memory.
227
    if (NULL == bottom)
228
        return NULL;
229
 
230
    size = roundup(size);
231
 
232
    do {
233
        CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
234
        dq = dq->next;
235
        if(0 == dq->size) {
236
            CYG_ASSERT(dq == &head, "bad free block");
237
            return NULL;
238
        }
239
    } while(dq->size < size);
240
 
241
    if( size == dq->size ) {
242
        // exact fit -- unlink from free list
243
        dq->prev->next = dq->next;
244
        dq->next->prev = dq->prev;
245
        alloced = (cyg_uint8 *)dq;
246
    } else {
247
 
248
        CYG_ASSERT( dq->size > size, "block found is too small");
249
 
250
        // allocate portion of memory from end of block
251
 
252
        dq->size -=size;
253
 
254
        // The portion left over has to be large enough to store a
255
        // struct memdq.  This is guaranteed because the alignment is
256
        // larger than the size of this structure.
257
 
258
        CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=dq->size ,
259
                "not enough space for list item" );
260
 
261
        alloced = (cyg_uint8 *)dq + dq->size;
262
    }
263
 
264
    CYG_ASSERT( bottom<=alloced && alloced<=top, "alloced outside pool" );
265
 
266
    // Set size on allocated block
267
 
268
    dq = (struct memdq *)alloced;
269
    dq->size = size;
270
    dq->next = dq->prev = (struct memdq *)0xd530d53; // magic number
271
 
272
    freemem -=size;
273
 
274
    cyg_uint8 *ptr = memdq2alloc( dq );
275
    CYG_ASSERT( ((CYG_ADDRESS)ptr & (alignment-1)) == 0,
276
                "returned memory not aligned" );
277
    CYG_MEMALLOC_FAIL_TEST(ptr==NULL, size);
278
 
279
    return ptr;
280
}
281
 
282
// -------------------------------------------------------------------------
283
// resize existing allocation, if oldsize is non-NULL, previous
284
// allocation size is placed into it. If previous size not available,
285
// it is set to 0. NB previous allocation size may have been rounded up.
286
// Occasionally the allocation can be adjusted *backwards* as well as,
287
// or instead of forwards, therefore the address of the resized
288
// allocation is returned, or NULL if no resizing was possible.
289
// Note that this differs from ::realloc() in that no attempt is
290
// made to call malloc() if resizing is not possible - that is left
291
// to higher layers. The data is copied from old to new though.
292
// The effects of alloc_ptr==NULL or newsize==0 are undefined
293
 
294
inline cyg_uint8 *
295
Cyg_Mempool_Variable_Implementation::resize_alloc( cyg_uint8 *alloc_ptr,
296
                                                   cyg_int32 newsize,
297
                                                   cyg_int32 *oldsize )
298
{
299
    cyg_uint8 *ret = NULL;
300
 
301
    CYG_REPORT_FUNCTION();
302
 
303
    CYG_CHECK_DATA_PTRC( alloc_ptr );
304
    if ( NULL != oldsize )
305
        CYG_CHECK_DATA_PTRC( oldsize );
306
 
307
    CYG_ASSERT( (bottom <= alloc_ptr) && (alloc_ptr <= top),
308
                "alloc_ptr outside pool" );
309
 
310
    struct memdq *dq=alloc2memdq( alloc_ptr );
311
 
312
    // check magic number in block for validity
313
    CYG_ASSERT( (dq->next == dq->prev) &&
314
                (dq->next == (struct memdq *)0xd530d53), "bad alloc_ptr" );
315
 
316
    newsize = roundup(newsize);
317
 
318
    if ( NULL != oldsize )
319
        *oldsize = dq->size;
320
 
321
    if ( newsize > dq->size ) {
322
        // see if we can increase the allocation size
323
        if ( (cyg_uint8 *)dq + newsize <= top ) { // obviously can't exceed pool
324
            struct memdq *nextdq = (struct memdq *)((cyg_uint8 *)dq + dq->size);
325
 
326
            if ( (nextdq->next != nextdq->prev) &&
327
                 (nextdq->size >= (newsize - dq->size)) ) {
328
                // it's free and it's big enough
329
                // we therefore temporarily join this block and *all* of
330
                // the next block, so that the code below can then split it
331
                nextdq->next->prev = nextdq->prev;
332
                nextdq->prev->next = nextdq->next;
333
                dq->size += nextdq->size;
334
                freemem -= nextdq->size;
335
            }
336
        } // if
337
    } // if
338
 
339
    // this is also used if the allocation size was increased and we need
340
    // to split it
341
    if ( newsize < dq->size ) {
342
        // We can shrink the allocation by splitting into smaller allocation and
343
        // new free block
344
        struct memdq *newdq = (struct memdq *)((cyg_uint8 *)dq + newsize);
345
 
346
        newdq->size = dq->size - newsize;
347
        dq->size = newsize;
348
 
349
        CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=newdq->size ,
350
                    "not enough space for list item" );
351
 
352
        // now return the new space back to the freelist
353
        insert_free_block( newdq );
354
 
355
        ret = alloc_ptr;
356
 
357
    } // if
358
    else if ( newsize == dq->size ) {
359
        ret = alloc_ptr;
360
    }
361
 
362
    CYG_MEMALLOC_FAIL_TEST(ret==NULL, newsize);
363
 
364
    return ret;
365
 
366
} // resize_alloc()
367
 
368
 
369
// -------------------------------------------------------------------------
370
// When no coalescing is done, free is simply a matter of using the
371
// freed memory as an element of the free list linking it in at the
372
// start. When coalescing, the free list is sorted
373
 
374
inline cyg_bool
375
Cyg_Mempool_Variable_Implementation::free( cyg_uint8 *p, cyg_int32 size )
376
{
377
    CYG_REPORT_FUNCTION();
378
 
379
    CYG_CHECK_DATA_PTRC( p );
380
 
381
    if (!((bottom <= p) && (p <= top)))
382
        return false;
383
 
384
    struct memdq *dq=alloc2memdq( p );
385
 
386
    // check magic number in block for validity
387
    if ( (dq->next != dq->prev) ||
388
         (dq->next != (struct memdq *)0xd530d53) )
389
        return false;
390
 
391
    if ( 0==size ) {
392
        size = dq->size;
393
    } else {
394
        size = roundup(size);
395
    }
396
 
397
    if( dq->size != size )
398
        return false;
399
 
400
    CYG_ASSERT( (cyg_int32)sizeof(struct memdq)<=size ,
401
                "not enough space for list item" );
402
 
403
    insert_free_block( dq );
404
 
405
    return true;
406
}
407
 
408
// -------------------------------------------------------------------------
409
 
410
inline void
411
Cyg_Mempool_Variable_Implementation::get_status(
412
    cyg_mempool_status_flag_t flags,
413
    Cyg_Mempool_Status &status )
414
{
415
    CYG_REPORT_FUNCTION();
416
 
417
// as quick or quicker to just set it, rather than test flag first
418
    status.arenabase = obase;
419
    if ( 0 != (flags & CYG_MEMPOOL_STAT_ARENASIZE) )
420
        status.arenasize = top - bottom;
421
    if ( 0 != (flags & CYG_MEMPOOL_STAT_TOTALALLOCATED) )
422
        status.totalallocated = (top-bottom) - freemem;
423
// as quick or quicker to just set it, rather than test flag first
424
    status.totalfree = freemem;
425
    if ( 0 != (flags & CYG_MEMPOOL_STAT_MAXFREE) ) {
426
        struct memdq *dq = &head;
427
        cyg_int32 mf = 0;
428
 
429
        do {
430
            CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
431
            dq = dq->next;
432
            if(0 == dq->size) {
433
                CYG_ASSERT(dq == &head, "bad free block");
434
                break;
435
            }
436
            if(dq->size > mf)
437
                mf = dq->size;
438
        } while(1);
439
        status.maxfree = mf - sizeof(struct memdq);
440
    }
441
// as quick or quicker to just set it, rather than test flag first
442
    status.origbase = obase;
443
// as quick or quicker to just set it, rather than test flag first
444
    status.origsize = osize;
445
 
446
    CYG_REPORT_RETURN();
447
 
448
} // get_status()
449
 
450
 
451
// -------------------------------------------------------------------------
452
#endif // ifndef CYGONCE_MEMALLOC_MVARIMPL_INL
453
// EOF mvarimpl.inl

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.