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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [services/] [memalloc/] [common/] [v2_0/] [include/] [mvarimpl.inl] - Blame information for rev 587

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

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

powered by: WebSVN 2.1.0

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