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