]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/memalloc/common/v2_0/include/mempoolt.inl
Initial revision
[karo-tx-redboot.git] / packages / services / memalloc / common / v2_0 / include / mempoolt.inl
1 #ifndef CYGONCE_KERNEL_MEMPOOLT_INL
2 #define CYGONCE_KERNEL_MEMPOOLT_INL
3
4 //==========================================================================
5 //
6 //      mempoolt.inl
7 //
8 //      Mempoolt (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:        hmt
48 // Date:        1998-02-10
49 // Purpose:     Define Mempoolt class interface
50
51 // Description: The class defined here provides the APIs for thread-safe,
52 //              kernel-savvy memory managers; make a class with the
53 //              underlying allocator as the template parameter.
54 // Usage:       #include <cyg/kernel/mempoolt.hxx>
55 //              
56 //
57 //####DESCRIPTIONEND####
58 //
59 //==========================================================================
60
61 #include <cyg/kernel/thread.inl>  // implementation eg. Cyg_Thread::self();
62 #include <cyg/kernel/sched.inl>   // implementation eg. Cyg_Scheduler::lock();
63
64 // -------------------------------------------------------------------------
65 // Constructor; we _require_ these arguments and just pass them through to
66 // the implementation memory pool in use.
67 template <class T>
68 Cyg_Mempoolt<T>::Cyg_Mempoolt(
69     cyg_uint8 *base,
70     cyg_int32 size,
71     CYG_ADDRWORD arg_thru)              // Constructor
72     : pool( base, size, arg_thru )
73 {
74 }
75
76
77 template <class T>
78 Cyg_Mempoolt<T>::~Cyg_Mempoolt()  // destructor
79 {
80     // Prevent preemption
81     Cyg_Scheduler::lock();
82             
83     while ( ! queue.empty() ) {
84         Cyg_Thread *thread = queue.dequeue();
85         thread->set_wake_reason( Cyg_Thread::DESTRUCT );
86         thread->wake();
87     }
88
89     // Unlock the scheduler and maybe switch threads
90     Cyg_Scheduler::unlock();    
91 }
92         
93 // -------------------------------------------------------------------------
94 // get some memory; wait if none available
95 template <class T>
96 inline cyg_uint8 *
97 Cyg_Mempoolt<T>::alloc( cyg_int32 size )
98 {
99     CYG_REPORT_FUNCTION();
100         
101     Cyg_Thread *self = Cyg_Thread::self();
102     
103     // Prevent preemption
104     Cyg_Scheduler::lock();
105     CYG_ASSERTCLASS( this, "Bad this pointer");
106     
107     // Loop while we got no memory, sleeping each time around the
108     // loop. This copes with the possibility of a higher priority thread
109     // grabbing the freed storage between the wakeup in free() and this
110     // thread actually starting.
111     cyg_uint8 *ret;
112     cyg_bool result = true;
113     while( result && (NULL == (ret = pool.alloc( size ))) ) {
114
115         CYG_MEMALLOC_FAIL(size);
116
117         self->set_sleep_reason( Cyg_Thread::WAIT );
118         self->sleep();
119         queue.enqueue( self );
120
121         CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
122                     "Called with non-zero scheduler lock");
123         
124         // Unlock scheduler and allow other threads to run
125         Cyg_Scheduler::unlock();
126         Cyg_Scheduler::lock();
127
128         CYG_ASSERTCLASS( this, "Bad this pointer");        
129
130         switch( self->get_wake_reason() )
131         {
132         case Cyg_Thread::DESTRUCT:
133         case Cyg_Thread::BREAK:
134             result = false;
135             break;
136             
137         case Cyg_Thread::EXIT:            
138             self->exit();
139             break;
140
141         default:
142             break;
143         }
144     }
145     CYG_ASSERTCLASS( this, "Bad this pointer");
146
147     if ( ! result )
148         ret = NULL;
149
150     // Unlock the scheduler and maybe switch threads
151     Cyg_Scheduler::unlock();
152     CYG_REPORT_RETVAL( ret );
153     return ret;
154 }
155
156 #ifdef CYGFUN_KERNEL_THREADS_TIMER
157 // -------------------------------------------------------------------------
158 // get some memory with a timeout
159 template <class T>
160 inline cyg_uint8 *
161 Cyg_Mempoolt<T>::alloc( cyg_int32 size, cyg_tick_count abs_timeout )
162 {
163     CYG_REPORT_FUNCTION();
164         
165     Cyg_Thread *self = Cyg_Thread::self();
166     
167     // Prevent preemption
168     Cyg_Scheduler::lock();
169     CYG_ASSERTCLASS( this, "Bad this pointer");
170     
171     // Loop while we got no memory, sleeping each time around the
172     // loop. This copes with the possibility of a higher priority thread
173     // grabbing the freed storage between the wakeup in free() and this
174     // thread actually starting.
175     cyg_uint8 *ret;
176     cyg_bool result = true;
177     // Set the timer _once_ outside the loop.
178     self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
179
180     // If the timeout is in the past, the wake reason will have been
181     // set to something other than NONE already. Set the result false
182     // to force an immediate return.
183     
184     if( self->get_wake_reason() != Cyg_Thread::NONE )
185         result = false;
186             
187     while( result && (NULL == (ret = pool.alloc( size ))) ) {
188         CYG_MEMALLOC_FAIL(size);
189
190         self->set_sleep_reason( Cyg_Thread::TIMEOUT );
191         self->sleep();
192         queue.enqueue( self );
193
194         CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(),
195                     "Called with non-zero scheduler lock");
196         
197         // Unlock scheduler and allow other threads to run
198         Cyg_Scheduler::unlock();
199         Cyg_Scheduler::lock();
200
201         CYG_ASSERTCLASS( this, "Bad this pointer");
202         switch( self->get_wake_reason() )
203         {
204         case Cyg_Thread::TIMEOUT:
205             result = false;
206             break;
207             
208         case Cyg_Thread::DESTRUCT:
209         case Cyg_Thread::BREAK:
210             result = false;
211             break;
212             
213         case Cyg_Thread::EXIT:            
214             self->exit();
215             break;
216
217         default:
218             break;
219         }
220     }
221
222     CYG_ASSERTCLASS( this, "Bad this pointer");
223
224     if ( ! result )
225         ret = NULL;
226
227     // clear the timer; if it actually fired, no worries.
228     self->clear_timer();
229
230     // Unlock the scheduler and maybe switch threads
231     Cyg_Scheduler::unlock();
232     CYG_REPORT_RETVAL( ret );
233     return ret;
234 }
235 #endif 
236
237 // -------------------------------------------------------------------------
238 // get some memory, return NULL if none available
239 template <class T>
240 inline cyg_uint8 *
241 Cyg_Mempoolt<T>::try_alloc( cyg_int32 size )
242 {
243     CYG_REPORT_FUNCTION();
244         
245     // Prevent preemption
246     Cyg_Scheduler::lock();
247     CYG_ASSERTCLASS( this, "Bad this pointer");
248     
249     cyg_uint8 *ret = pool.alloc( size );
250
251     CYG_ASSERTCLASS( this, "Bad this pointer");
252
253     // Unlock the scheduler and maybe switch threads
254     Cyg_Scheduler::unlock();
255     CYG_REPORT_RETVAL( ret );
256
257     CYG_MEMALLOC_FAIL_TEST(ret==NULL, size);
258
259     return ret;
260 }
261     
262     
263 // -------------------------------------------------------------------------
264 // free the memory back to the pool
265 template <class T>
266 cyg_bool
267 Cyg_Mempoolt<T>::free( cyg_uint8 *p, cyg_int32 size )
268 {
269     // Prevent preemption
270     Cyg_Scheduler::lock();
271     CYG_ASSERTCLASS( this, "Bad this pointer");
272     
273     cyg_int32 ret = pool.free( p, size );
274
275     CYG_ASSERTCLASS( this, "Bad this pointer");
276
277     while ( ret && !queue.empty() ) {
278         // we succeeded and there are people waiting
279         Cyg_Thread *thread = queue.dequeue();
280
281         CYG_ASSERTCLASS( thread, "Bad thread pointer");
282
283         // we wake them all up (ie. broadcast) to cope with variable block
284         // allocators freeing a big block when lots of small allocs wait.
285         thread->set_wake_reason( Cyg_Thread::DONE );
286         thread->wake();
287         // we cannot yield here; if a higher prio thread can't satisfy its
288         // request it would re-queue and we would loop forever
289     }
290     // Unlock the scheduler and maybe switch threads
291     Cyg_Scheduler::unlock();
292     return ret;
293 }
294
295 // -------------------------------------------------------------------------
296 // if applicable: return -1 if not fixed size
297 template <class T>
298 inline cyg_int32
299 Cyg_Mempoolt<T>::get_blocksize()
300 {
301     // there should not be any atomicity issues here
302     return pool.get_blocksize();
303 }
304
305 // -------------------------------------------------------------------------
306 // these two are obvious and generic, but need atomicity protection (maybe)
307 template <class T>
308 inline cyg_int32
309 Cyg_Mempoolt<T>::get_totalmem()
310 {
311     // Prevent preemption
312     Cyg_Scheduler::lock();
313     CYG_ASSERTCLASS( this, "Bad this pointer");
314     
315     cyg_int32 ret = pool.get_totalmem();
316
317     // Unlock the scheduler and maybe switch threads
318     Cyg_Scheduler::unlock();
319     return ret;
320 }
321
322 template <class T>
323 inline cyg_int32
324 Cyg_Mempoolt<T>::get_freemem()
325 {
326     // Prevent preemption
327     Cyg_Scheduler::lock();
328     CYG_ASSERTCLASS( this, "Bad this pointer");
329     
330     cyg_int32 ret = pool.get_freemem();
331
332     // Unlock the scheduler and maybe switch threads
333     Cyg_Scheduler::unlock();
334     return ret;
335 }
336
337 // -------------------------------------------------------------------------
338 // get information about the construction parameters for external
339 // freeing after the destruction of the holding object
340 template <class T>
341 inline void
342 Cyg_Mempoolt<T>::get_arena(
343     cyg_uint8 * &base, cyg_int32 &size, CYG_ADDRWORD &arg_thru )
344 {
345     // Prevent preemption
346     Cyg_Scheduler::lock();
347     CYG_ASSERTCLASS( this, "Bad this pointer");
348     
349     pool.get_arena( base, size, arg_thru );
350
351     // Unlock the scheduler and maybe switch threads
352     Cyg_Scheduler::unlock();
353 }
354
355 // -------------------------------------------------------------------------
356 // Return the size of the memory allocation (previously returned 
357 // by alloc() or try_alloc() ) at ptr. Returns -1 if not found
358 template <class T>
359 cyg_int32
360 Cyg_Mempoolt<T>::get_allocation_size( cyg_uint8 *ptr )
361 {
362     cyg_int32 ret;
363     
364     // Prevent preemption
365     Cyg_Scheduler::lock();
366     CYG_ASSERTCLASS( this, "Bad this pointer");
367     
368     ret = pool.get_allocation_size( ptr );
369
370     // Unlock the scheduler and maybe switch threads
371     Cyg_Scheduler::unlock();
372
373     return ret;
374 }
375
376 // -------------------------------------------------------------------------
377 // debugging/assert function
378
379 #ifdef CYGDBG_USE_ASSERTS
380
381 template <class T>
382 inline cyg_bool
383 Cyg_Mempoolt<T>::check_this(cyg_assert_class_zeal zeal) const
384 {
385     CYG_REPORT_FUNCTION();
386
387     if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
388         // then the whole thing is invalid, and we know it.
389         // so return OK, since this check should NOT make an error.
390         return true;
391
392     // check that we have a non-NULL pointer first
393     if( this == NULL ) return false;
394
395     return true;
396 }
397 #endif
398
399 // -------------------------------------------------------------------------
400 #endif // ifndef CYGONCE_KERNEL_MEMPOOLT_INL
401 // EOF mempoolt.inl