source: SVN/cambria/redboot/packages/services/memalloc/common/current/include/mempolt2.inl @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 12.5 KB
Line 
1#ifndef CYGONCE_MEMALLOC_MEMPOLT2_INL
2#define CYGONCE_MEMALLOC_MEMPOLT2_INL
3
4//==========================================================================
5//
6//      mempolt2.inl
7//
8//      Mempolt2 (Memory pool template) 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 Mempolt2 class interface
50// Description:  The class defined here provides the APIs for thread-safe,
51//               kernel-savvy memory managers; make a class with the
52//               underlying allocator as the template parameter.
53// Usage:        #include <cyg/memalloc/mempolt2.hxx>
54//             
55//
56//####DESCRIPTIONEND####
57//
58//==========================================================================
59
60#include <cyg/infra/cyg_ass.h>    // assertion support
61#include <cyg/infra/cyg_trac.h>   // tracing support
62#include <cyg/kernel/thread.inl>  // implementation eg. Cyg_Thread::self();
63#include <cyg/kernel/sched.inl>   // implementation eg. Cyg_Scheduler::lock();
64
65// -------------------------------------------------------------------------
66// Constructor; we _require_ these arguments and just pass them through to
67// the implementation memory pool in use.
68template <class T>
69Cyg_Mempolt2<T>::Cyg_Mempolt2(
70    cyg_uint8 *base,
71    cyg_int32 size,
72    CYG_ADDRWORD arg_thru)              // Constructor
73    : pool( base, size, arg_thru )
74{
75}
76
77
78template <class T>
79Cyg_Mempolt2<T>::~Cyg_Mempolt2()  // destructor
80{
81    // Prevent preemption
82    Cyg_Scheduler::lock();
83           
84    while ( ! queue.empty() ) {
85        Cyg_Thread *thread = queue.dequeue();
86        thread->set_wake_reason( Cyg_Thread::DESTRUCT );
87        thread->wake();
88    }
89
90    // Unlock the scheduler and maybe switch threads
91    Cyg_Scheduler::unlock();   
92}
93       
94// -------------------------------------------------------------------------
95// get some memory; wait if none available
96template <class T>
97inline cyg_uint8 *
98Cyg_Mempolt2<T>::alloc( cyg_int32 size )
99{
100    CYG_REPORT_FUNCTION();
101       
102    // Prevent preemption
103    Cyg_Scheduler::lock();
104    CYG_ASSERTCLASS( this, "Bad this pointer");
105   
106    cyg_uint8 *ret;
107    ret = pool.try_alloc( size );
108    if ( ret ) {
109        Cyg_Scheduler::unlock();
110        CYG_ASSERTCLASS( this, "Bad this pointer");
111        CYG_REPORT_RETVAL( ret );
112        return ret;
113    }
114
115    Cyg_Thread *self = Cyg_Thread::self();
116
117    Mempolt2WaitInfo waitinfo( size );
118
119    CYG_MEMALLOC_FAIL(size);
120
121    self->set_wait_info( (CYG_ADDRWORD)&waitinfo );
122    self->set_sleep_reason( Cyg_Thread::WAIT );
123    self->sleep();
124    queue.enqueue( self );
125
126    CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
127                "Called with non-zero scheduler lock");
128       
129    // Unlock scheduler and allow other threads to run
130    Cyg_Scheduler::unlock();
131
132    cyg_bool result = true; // just used as a flag here
133    switch( self->get_wake_reason() )
134    {
135    case Cyg_Thread::DESTRUCT:
136    case Cyg_Thread::BREAK:
137        result = false;
138        break;
139       
140    case Cyg_Thread::EXIT:           
141        self->exit();
142        break;
143       
144    default:
145        break;
146    }
147
148    if ( ! result )
149        ret = NULL;
150    else
151        ret = waitinfo.addr;
152
153    CYG_ASSERT( (!result) || (NULL != ret), "Good result but no alloc!" );
154    CYG_ASSERTCLASS( this, "Bad this pointer");
155    CYG_REPORT_RETVAL( ret );
156    return ret;
157}
158
159#ifdef CYGFUN_KERNEL_THREADS_TIMER
160// -------------------------------------------------------------------------
161// get some memory with a timeout
162template <class T>
163inline cyg_uint8 *
164Cyg_Mempolt2<T>::alloc( cyg_int32 size, cyg_tick_count abs_timeout )
165{
166    CYG_REPORT_FUNCTION();
167   
168    // Prevent preemption
169    Cyg_Scheduler::lock();
170    CYG_ASSERTCLASS( this, "Bad this pointer");
171   
172    cyg_uint8 *ret;
173    ret = pool.try_alloc( size );
174    if ( ret ) {
175        Cyg_Scheduler::unlock();
176        CYG_ASSERTCLASS( this, "Bad this pointer");
177        CYG_REPORT_RETVAL( ret );
178        return ret;
179    }
180
181    Cyg_Thread *self = Cyg_Thread::self();
182
183    Mempolt2WaitInfo waitinfo( size );
184
185    self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
186
187    // If the timeout is in the past, the wake reason will have been set to
188    // something other than NONE already. If so, skip the wait and go
189    // straight to unlock.
190   
191    if( Cyg_Thread::NONE == self->get_wake_reason() ) {
192
193        CYG_MEMALLOC_FAIL(size);
194
195        self->set_wait_info( (CYG_ADDRWORD)&waitinfo );
196        self->sleep();
197        queue.enqueue( self );
198    }
199
200    CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
201                "Called with non-zero scheduler lock");
202       
203    // Unlock scheduler and allow other threads to run
204    Cyg_Scheduler::unlock();
205
206    // clear the timer; if it actually fired, no worries.
207    self->clear_timer();
208
209    cyg_bool result = true; // just used as a flag here
210    switch( self->get_wake_reason() )
211    {
212    case Cyg_Thread::TIMEOUT:
213        result = false;
214        break;
215           
216    case Cyg_Thread::DESTRUCT:
217    case Cyg_Thread::BREAK:
218        result = false;
219        break;
220           
221    case Cyg_Thread::EXIT:           
222        self->exit();
223        break;
224
225    default:
226        break;
227    }
228
229    if ( ! result )
230        ret = NULL;
231    else
232        ret = waitinfo.addr;
233
234    CYG_ASSERT( (!result) || (NULL != ret), "Good result but no alloc!" );
235    CYG_ASSERTCLASS( this, "Bad this pointer");
236    CYG_REPORT_RETVAL( ret );
237    return ret;
238}
239#endif
240
241// -------------------------------------------------------------------------
242// get some memory, return NULL if none available
243template <class T>
244inline cyg_uint8 *
245Cyg_Mempolt2<T>::try_alloc( cyg_int32 size )
246{
247    CYG_REPORT_FUNCTION();
248       
249    // Prevent preemption
250    Cyg_Scheduler::lock();
251    CYG_ASSERTCLASS( this, "Bad this pointer");
252   
253    cyg_uint8 *ret = pool.try_alloc( size );
254
255    CYG_ASSERTCLASS( this, "Bad this pointer");
256
257    // Unlock the scheduler and maybe switch threads
258    Cyg_Scheduler::unlock();
259
260    CYG_MEMALLOC_FAIL_TEST(ret==NULL, size);
261
262    return ret;
263}
264   
265   
266// -------------------------------------------------------------------------
267// resize existing allocation, if oldsize is non-NULL, previous
268// allocation size is placed into it. If previous size not available,
269// it is set to 0. NB previous allocation size may have been rounded up.
270// Occasionally the allocation can be adjusted *backwards* as well as,
271// or instead of forwards, therefore the address of the resized
272// allocation is returned, or NULL if no resizing was possible.
273// Note that this differs from ::realloc() in that no attempt is
274// made to call malloc() if resizing is not possible - that is left
275// to higher layers. The data is copied from old to new though.
276// The effects of alloc_ptr==NULL or newsize==0 are undefined
277template <class T>
278cyg_uint8 *
279Cyg_Mempolt2<T>::resize_alloc( cyg_uint8 *alloc_ptr, cyg_int32 newsize,
280                               cyg_int32 *oldsize )
281{
282    CYG_REPORT_FUNCTION();
283       
284    // Prevent preemption
285    Cyg_Scheduler::lock();
286    CYG_ASSERTCLASS( this, "Bad this pointer");
287   
288    cyg_uint8 *ret = pool.resize_alloc( alloc_ptr, newsize, oldsize );
289
290    CYG_ASSERTCLASS( this, "Bad this pointer");
291
292    // Unlock the scheduler and maybe switch threads
293    Cyg_Scheduler::unlock();
294
295    CYG_MEMALLOC_FAIL_TEST(ret==NULL, newsize);
296
297    return ret;
298}
299   
300   
301// -------------------------------------------------------------------------
302// free the memory back to the pool
303template <class T>
304cyg_bool
305Cyg_Mempolt2<T>::free( cyg_uint8 *p, cyg_int32 size )
306{
307    CYG_REPORT_FUNCTION();
308    // Prevent preemption
309    Cyg_Scheduler::lock();
310    CYG_ASSERTCLASS( this, "Bad this pointer");
311   
312    cyg_int32 ret = pool.free( p, size );
313
314    // anyone waiting?
315    if ( !(queue.empty()) ) {
316        Mempolt2WaitInfo *p;
317        Cyg_Thread     *thread;
318
319#ifdef CYGIMP_MEM_T_ONEFREE_TO_ONEALLOC
320        thread = queue.dequeue();
321        p = (Mempolt2WaitInfo *)(thread->get_wait_info());
322        CYG_ASSERT( NULL == p->addr, "Thread already awoken?" );
323
324        cyg_uint8 *mem;
325        mem = pool.try_alloc( p->size );
326        CYG_ASSERT( NULL != mem, "That should have succeeded" );
327        thread->set_wake_reason( Cyg_Thread::DONE );
328        thread->wake();
329        // return the successful value to it
330        p->addr = mem;
331#else
332        Cyg_ThreadQueue holding;
333        do {
334            thread = queue.dequeue();
335            p = (Mempolt2WaitInfo *)(thread->get_wait_info());
336            CYG_ASSERT( NULL == p->addr, "Thread already awoken?" );
337
338            cyg_uint8 *mem;
339            if ( NULL != (mem = pool.try_alloc( p->size )) ) {
340                // success!  awaken the thread
341                thread->set_wake_reason( Cyg_Thread::DONE );
342                thread->wake();
343                // return the successful value to it
344                p->addr = mem;
345            }
346            else {
347                // preserve the entry on the holding queue
348                holding.enqueue( thread );
349            }
350        } while ( !(queue.empty()) );
351           
352        // Now re-queue the unaffected threads back into the pool queue
353        // (no pun intended)
354        while ( !(holding.empty()) ) {
355            queue.enqueue( holding.dequeue() );
356        }
357#endif // CYGIMP_MEM_T_ONEFREE_TO_ONEALLOC
358    }
359    // Unlock the scheduler and maybe switch threads
360    Cyg_Scheduler::unlock();
361    CYG_REPORT_RETVAL( ret );
362    return ret;
363}
364
365// -------------------------------------------------------------------------
366// Get memory pool status
367// Needs atomicity protection (maybe)
368template <class T>
369inline void
370Cyg_Mempolt2<T>::get_status( cyg_mempool_status_flag_t flags,
371                             Cyg_Mempool_Status &status )
372{
373    // Prevent preemption
374    Cyg_Scheduler::lock();
375    CYG_ASSERTCLASS( this, "Bad this pointer");
376   
377    if (0 != (flags & CYG_MEMPOOL_STAT_WAITING)) {
378        status.waiting = (0 == queue.empty());
379    }
380    pool.get_status(flags, status);
381
382    // Unlock the scheduler and maybe switch threads
383    Cyg_Scheduler::unlock();
384}
385
386// -------------------------------------------------------------------------
387// debugging/assert function
388
389#ifdef CYGDBG_USE_ASSERTS
390
391template <class T>
392inline cyg_bool
393Cyg_Mempolt2<T>::check_this(cyg_assert_class_zeal zeal) const
394{
395    CYG_REPORT_FUNCTION();
396       
397    if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
398        // then the whole thing is invalid, and we know it.
399        // so return OK, since this check should NOT make an error.
400        return true;
401
402    // check that we have a non-NULL pointer first
403    if( this == NULL ) return false;
404
405    return true;
406}
407#endif
408
409// -------------------------------------------------------------------------
410#endif // ifndef CYGONCE_MEMALLOC_MEMPOLT2_INL
411// EOF mempolt2.inl
Note: See TracBrowser for help on using the repository browser.