]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/memalloc/common/v2_0/include/mempolt2.inl
Initial revision
[karo-tx-redboot.git] / packages / services / memalloc / common / v2_0 / include / mempolt2.inl
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.
68 template <class T>
69 Cyg_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
78 template <class T>
79 Cyg_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
96 template <class T>
97 inline cyg_uint8 *
98 Cyg_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
162 template <class T>
163 inline cyg_uint8 *
164 Cyg_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
243 template <class T>
244 inline cyg_uint8 *
245 Cyg_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
277 template <class T>
278 cyg_uint8 *
279 Cyg_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
303 template <class T>
304 cyg_bool
305 Cyg_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)
368 template <class T>
369 inline void
370 Cyg_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
391 template <class T>
392 inline cyg_bool
393 Cyg_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