|
0
|
1 #ifndef CYGONCE_KERNEL_MEMPOLT2_INL |
|
|
2 #define CYGONCE_KERNEL_MEMPOLT2_INL |
|
|
3 |
|
|
4 //========================================================================== |
|
|
5 // |
|
|
6 // mempolt2.inl |
|
|
7 // |
|
|
8 // Mempolt2 (Memory pool template) class declarations |
|
|
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 |
|
|
28 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. |
|
|
29 // ------------------------------------------- |
|
|
30 // |
|
|
31 //####COPYRIGHTEND#### |
|
|
32 //========================================================================== |
|
|
33 //#####DESCRIPTIONBEGIN#### |
|
|
34 // |
|
|
35 // Author(s): hmt |
|
|
36 // Contributors: hmt |
|
|
37 // Date: 1998-02-10 |
|
|
38 // Purpose: Define Mempolt2 class interface |
|
|
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. |
|
|
43 // Usage: #include <cyg/kernel/mempolt2.hxx> |
|
|
44 // |
|
|
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_Mempolt2<T>::Cyg_Mempolt2( |
|
|
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_Mempolt2<T>::~Cyg_Mempolt2() // 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_Mempolt2<T>::alloc( cyg_int32 size ) |
|
|
87 { |
|
|
88 CYG_REPORT_FUNCTION(); |
|
|
89 |
|
|
90 // Prevent preemption |
|
|
91 Cyg_Scheduler::lock(); |
|
|
92 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
93 |
|
|
94 cyg_uint8 *ret; |
|
|
95 ret = pool.alloc( size ); |
|
|
96 if ( ret ) { |
|
|
97 Cyg_Scheduler::unlock(); |
|
|
98 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
99 CYG_REPORT_RETVAL( ret ); |
|
|
100 return ret; |
|
|
101 } |
|
|
102 |
|
|
103 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
104 |
|
|
105 Mempolt2WaitInfo waitinfo( size ); |
|
|
106 |
|
|
107 self->set_wait_info( (CYG_ADDRWORD)&waitinfo ); |
|
|
108 self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
|
109 self->sleep(); |
|
|
110 queue.enqueue( self ); |
|
|
111 |
|
|
112 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), |
|
|
113 "Called with non-zero scheduler lock"); |
|
|
114 |
|
|
115 // Unlock scheduler and allow other threads to run |
|
|
116 Cyg_Scheduler::unlock(); |
|
|
117 |
|
|
118 cyg_bool result = true; // just used as a flag here |
|
|
119 switch( self->get_wake_reason() ) |
|
|
120 { |
|
|
121 case Cyg_Thread::DESTRUCT: |
|
|
122 case Cyg_Thread::BREAK: |
|
|
123 result = false; |
|
|
124 break; |
|
|
125 |
|
|
126 case Cyg_Thread::EXIT: |
|
|
127 self->exit(); |
|
|
128 break; |
|
|
129 |
|
|
130 default: |
|
|
131 break; |
|
|
132 } |
|
|
133 |
|
|
134 if ( ! result ) |
|
|
135 ret = NULL; |
|
|
136 else |
|
|
137 ret = waitinfo.addr; |
|
|
138 |
|
|
139 CYG_ASSERT( (!result) || (NULL != ret), "Good result but no alloc!" ); |
|
|
140 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
141 CYG_REPORT_RETVAL( ret ); |
|
|
142 return ret; |
|
|
143 } |
|
|
144 |
|
|
145 #ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
|
146 // ------------------------------------------------------------------------- |
|
|
147 // get some memory with a timeout |
|
|
148 template <class T> |
|
|
149 inline cyg_uint8 * |
|
|
150 Cyg_Mempolt2<T>::alloc( cyg_int32 size, cyg_tick_count abs_timeout ) |
|
|
151 { |
|
|
152 CYG_REPORT_FUNCTION(); |
|
|
153 |
|
|
154 // Prevent preemption |
|
|
155 Cyg_Scheduler::lock(); |
|
|
156 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
157 |
|
|
158 cyg_uint8 *ret; |
|
|
159 ret = pool.alloc( size ); |
|
|
160 if ( ret ) { |
|
|
161 Cyg_Scheduler::unlock(); |
|
|
162 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
163 CYG_REPORT_RETVAL( ret ); |
|
|
164 return ret; |
|
|
165 } |
|
|
166 |
|
|
167 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
168 |
|
|
169 Mempolt2WaitInfo waitinfo( size ); |
|
|
170 |
|
|
171 self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); |
|
|
172 |
|
|
173 // If the timeout is in the past, the wake reason will have been set to |
|
|
174 // something other than NONE already. If so, skip the wait and go |
|
|
175 // straight to unlock. |
|
|
176 |
|
|
177 if( Cyg_Thread::NONE == self->get_wake_reason() ) { |
|
|
178 self->set_wait_info( (CYG_ADDRWORD)&waitinfo ); |
|
|
179 self->sleep(); |
|
|
180 queue.enqueue( self ); |
|
|
181 } |
|
|
182 |
|
|
183 CYG_ASSERT( 1 == Cyg_Scheduler::get_sched_lock(), |
|
|
184 "Called with non-zero scheduler lock"); |
|
|
185 |
|
|
186 // Unlock scheduler and allow other threads to run |
|
|
187 Cyg_Scheduler::unlock(); |
|
|
188 |
|
|
189 // clear the timer; if it actually fired, no worries. |
|
|
190 self->clear_timer(); |
|
|
191 |
|
|
192 cyg_bool result = true; // just used as a flag here |
|
|
193 switch( self->get_wake_reason() ) |
|
|
194 { |
|
|
195 case Cyg_Thread::TIMEOUT: |
|
|
196 result = false; |
|
|
197 break; |
|
|
198 |
|
|
199 case Cyg_Thread::DESTRUCT: |
|
|
200 case Cyg_Thread::BREAK: |
|
|
201 result = false; |
|
|
202 break; |
|
|
203 |
|
|
204 case Cyg_Thread::EXIT: |
|
|
205 self->exit(); |
|
|
206 break; |
|
|
207 |
|
|
208 default: |
|
|
209 break; |
|
|
210 } |
|
|
211 |
|
|
212 if ( ! result ) |
|
|
213 ret = NULL; |
|
|
214 else |
|
|
215 ret = waitinfo.addr; |
|
|
216 |
|
|
217 CYG_ASSERT( (!result) || (NULL != ret), "Good result but no alloc!" ); |
|
|
218 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
219 CYG_REPORT_RETVAL( ret ); |
|
|
220 return ret; |
|
|
221 } |
|
|
222 #endif |
|
|
223 |
|
|
224 // ------------------------------------------------------------------------- |
|
|
225 // get some memory, return NULL if none available |
|
|
226 template <class T> |
|
|
227 inline cyg_uint8 * |
|
|
228 Cyg_Mempolt2<T>::try_alloc( cyg_int32 size ) |
|
|
229 { |
|
|
230 CYG_REPORT_FUNCTION(); |
|
|
231 |
|
|
232 // Prevent preemption |
|
|
233 Cyg_Scheduler::lock(); |
|
|
234 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
235 |
|
|
236 cyg_uint8 *ret = pool.alloc( size ); |
|
|
237 |
|
|
238 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
239 |
|
|
240 // Unlock the scheduler and maybe switch threads |
|
|
241 Cyg_Scheduler::unlock(); |
|
|
242 return ret; |
|
|
243 } |
|
|
244 |
|
|
245 |
|
|
246 // ------------------------------------------------------------------------- |
|
|
247 // free the memory back to the pool |
|
|
248 template <class T> |
|
|
249 cyg_bool |
|
|
250 Cyg_Mempolt2<T>::free( cyg_uint8 *p, cyg_int32 size ) |
|
|
251 { |
|
|
252 CYG_REPORT_FUNCTION(); |
|
|
253 // Prevent preemption |
|
|
254 Cyg_Scheduler::lock(); |
|
|
255 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
256 |
|
|
257 cyg_int32 ret = pool.free( p, size ); |
|
|
258 |
|
|
259 // anyone waiting? |
|
|
260 if ( !(queue.empty()) ) { |
|
|
261 Mempolt2WaitInfo *p; |
|
|
262 Cyg_Thread *thread; |
|
|
263 |
|
|
264 #ifdef CYGIMP_MEM_T_ONEFREE_TO_ONEALLOC |
|
|
265 thread = queue.dequeue(); |
|
|
266 p = (Mempolt2WaitInfo *)(thread->get_wait_info()); |
|
|
267 CYG_ASSERT( NULL == p->addr, "Thread already awoken?" ); |
|
|
268 |
|
|
269 cyg_uint8 *mem; |
|
|
270 mem = pool.alloc( p->size ); |
|
|
271 CYG_ASSERT( NULL != mem, "That should have succeeded" ); |
|
|
272 thread->set_wake_reason( Cyg_Thread::DONE ); |
|
|
273 thread->wake(); |
|
|
274 // return the successful value to it |
|
|
275 p->addr = mem; |
|
|
276 #else |
|
|
277 Cyg_ThreadQueue holding; |
|
|
278 do { |
|
|
279 thread = queue.dequeue(); |
|
|
280 p = (Mempolt2WaitInfo *)(thread->get_wait_info()); |
|
|
281 CYG_ASSERT( NULL == p->addr, "Thread already awoken?" ); |
|
|
282 |
|
|
283 cyg_uint8 *mem; |
|
|
284 if ( NULL != (mem = pool.alloc( p->size )) ) { |
|
|
285 // success! awaken the thread |
|
|
286 thread->set_wake_reason( Cyg_Thread::DONE ); |
|
|
287 thread->wake(); |
|
|
288 // return the successful value to it |
|
|
289 p->addr = mem; |
|
|
290 } |
|
|
291 else { |
|
|
292 // preserve the entry on the holding queue |
|
|
293 holding.enqueue( thread ); |
|
|
294 } |
|
|
295 } while ( !(queue.empty()) ); |
|
|
296 |
|
|
297 // Now re-queue the unaffected threads back into the pool queue |
|
|
298 // (no pun intended) |
|
|
299 while ( !(holding.empty()) ) { |
|
|
300 queue.enqueue( holding.dequeue() ); |
|
|
301 } |
|
|
302 #endif // CYGIMP_MEM_T_ONEFREE_TO_ONEALLOC |
|
|
303 } |
|
|
304 // Unlock the scheduler and maybe switch threads |
|
|
305 Cyg_Scheduler::unlock(); |
|
|
306 CYG_REPORT_RETVAL( ret ); |
|
|
307 return ret; |
|
|
308 } |
|
|
309 |
|
|
310 // ------------------------------------------------------------------------- |
|
|
311 // if applicable: return -1 if not fixed size |
|
|
312 template <class T> |
|
|
313 inline cyg_int32 |
|
|
314 Cyg_Mempolt2<T>::get_blocksize() |
|
|
315 { |
|
|
316 // there should not be any atomicity issues here |
|
|
317 return pool.get_blocksize(); |
|
|
318 } |
|
|
319 |
|
|
320 // ------------------------------------------------------------------------- |
|
|
321 // these two are obvious and generic, but need atomicity protection (maybe) |
|
|
322 template <class T> |
|
|
323 inline cyg_int32 |
|
|
324 Cyg_Mempolt2<T>::get_totalmem() |
|
|
325 { |
|
|
326 // Prevent preemption |
|
|
327 Cyg_Scheduler::lock(); |
|
|
328 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
329 |
|
|
330 cyg_int32 ret = pool.get_totalmem(); |
|
|
331 |
|
|
332 // Unlock the scheduler and maybe switch threads |
|
|
333 Cyg_Scheduler::unlock(); |
|
|
334 return ret; |
|
|
335 } |
|
|
336 |
|
|
337 template <class T> |
|
|
338 inline cyg_int32 |
|
|
339 Cyg_Mempolt2<T>::get_freemem() |
|
|
340 { |
|
|
341 // Prevent preemption |
|
|
342 Cyg_Scheduler::lock(); |
|
|
343 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
344 |
|
|
345 cyg_int32 ret = pool.get_freemem(); |
|
|
346 |
|
|
347 // Unlock the scheduler and maybe switch threads |
|
|
348 Cyg_Scheduler::unlock(); |
|
|
349 return ret; |
|
|
350 } |
|
|
351 |
|
|
352 // ------------------------------------------------------------------------- |
|
|
353 // get information about the construction parameters for external |
|
|
354 // freeing after the destruction of the holding object |
|
|
355 template <class T> |
|
|
356 inline void |
|
|
357 Cyg_Mempolt2<T>::get_arena( |
|
|
358 cyg_uint8 * &base, cyg_int32 &size, CYG_ADDRWORD &arg_thru ) |
|
|
359 { |
|
|
360 // Prevent preemption |
|
|
361 Cyg_Scheduler::lock(); |
|
|
362 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
363 |
|
|
364 pool.get_arena( base, size, arg_thru ); |
|
|
365 |
|
|
366 // Unlock the scheduler and maybe switch threads |
|
|
367 Cyg_Scheduler::unlock(); |
|
|
368 } |
|
|
369 |
|
|
370 // ------------------------------------------------------------------------- |
|
|
371 // Return the size of the memory allocation (previously returned |
|
|
372 // by alloc() or try_alloc() ) at ptr. Returns -1 if not found |
|
|
373 template <class T> |
|
|
374 cyg_int32 |
|
|
375 Cyg_Mempolt2<T>::get_allocation_size( cyg_uint8 *ptr ) |
|
|
376 { |
|
|
377 cyg_int32 ret; |
|
|
378 |
|
|
379 // Prevent preemption |
|
|
380 Cyg_Scheduler::lock(); |
|
|
381 CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
|
382 |
|
|
383 ret = pool.get_allocation_size( ptr ); |
|
|
384 |
|
|
385 // Unlock the scheduler and maybe switch threads |
|
|
386 Cyg_Scheduler::unlock(); |
|
|
387 |
|
|
388 return ret; |
|
|
389 } |
|
|
390 |
|
|
391 // ------------------------------------------------------------------------- |
|
|
392 // debugging/assert function |
|
|
393 |
|
|
394 #ifdef CYGDBG_USE_ASSERTS |
|
|
395 |
|
|
396 template <class T> |
|
|
397 inline cyg_bool |
|
|
398 Cyg_Mempolt2<T>::check_this(cyg_assert_class_zeal zeal) |
|
|
399 { |
|
|
400 CYG_REPORT_FUNCTION(); |
|
|
401 |
|
|
402 if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() ) |
|
|
403 // then the whole thing is invalid, and we know it. |
|
|
404 // so return OK, since this check should NOT make an error. |
|
|
405 return true; |
|
|
406 |
|
|
407 // check that we have a non-NULL pointer first |
|
|
408 if( this == NULL ) return false; |
|
|
409 |
|
|
410 return true; |
|
|
411 } |
|
|
412 #endif |
|
|
413 |
|
|
414 // ------------------------------------------------------------------------- |
|
|
415 #endif // ifndef CYGONCE_KERNEL_MEMPOLT2_INL |
|
|
416 // EOF mempolt2.inl |