FreeCalypso > hg > freecalypso-sw
comparison nuc-fw/nucleus/dms.c @ 79:947b1f473960
beginning of nuc-fw
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 11 Aug 2013 07:17:25 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
78:2c266d4339ff | 79:947b1f473960 |
---|---|
1 /*************************************************************************/ | |
2 /* */ | |
3 /* Copyright Mentor Graphics Corporation 2002 */ | |
4 /* All Rights Reserved. */ | |
5 /* */ | |
6 /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ | |
7 /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ | |
8 /* SUBJECT TO LICENSE TERMS. */ | |
9 /* */ | |
10 /*************************************************************************/ | |
11 | |
12 /*************************************************************************/ | |
13 /* */ | |
14 /* FILE NAME VERSION */ | |
15 /* */ | |
16 /* dms.c Nucleus PLUS 1.14 */ | |
17 /* */ | |
18 /* COMPONENT */ | |
19 /* */ | |
20 /* DM - Dynamic Memory Management */ | |
21 /* */ | |
22 /* DESCRIPTION */ | |
23 /* */ | |
24 /* This file contains the supplemental routines for the Dynamic */ | |
25 /* Memory Management component. */ | |
26 /* */ | |
27 /* DATA STRUCTURES */ | |
28 /* */ | |
29 /* None */ | |
30 /* */ | |
31 /* FUNCTIONS */ | |
32 /* */ | |
33 /* DMS_Allocate_Aligned_Memory Allocate an aligned memory */ | |
34 /* block from a dynamic */ | |
35 /* memory pool */ | |
36 /* DEPENDENCIES */ | |
37 /* */ | |
38 /* cs_extr.h Common Service functions */ | |
39 /* tc_extr.h Thread Control functions */ | |
40 /* dm_extr.h Partition functions */ | |
41 /* hi_extr.h History functions */ | |
42 /* */ | |
43 /* HISTORY */ | |
44 /* */ | |
45 /* DATE REMARKS */ | |
46 /* */ | |
47 /* 01-15-1999 Created initial revision */ | |
48 /* 03-26-1999 Released 1.11m (new release */ | |
49 /* numbering scheme) */ | |
50 /* 04-17-2002 Released version 1.13m */ | |
51 /* 11-07-2002 Released version 1.14 */ | |
52 /*************************************************************************/ | |
53 #define NU_SOURCE_FILE | |
54 | |
55 #include "cs_extr.h" /* Common service functions */ | |
56 #include "tc_extr.h" /* Thread control functions */ | |
57 #include "dm_extr.h" /* Dynamic memory functions */ | |
58 #include "hi_extr.h" /* History functions */ | |
59 #include "profiler.h" /* ProView interface */ | |
60 | |
61 | |
62 /* Define external inner-component global data references. */ | |
63 | |
64 | |
65 /* Define internal component function prototypes. */ | |
66 VOID DMC_Cleanup(VOID *information); | |
67 | |
68 | |
69 /*************************************************************************/ | |
70 /* */ | |
71 /* FUNCTION */ | |
72 /* */ | |
73 /* DMS_Allocate_Aligned_Memory */ | |
74 /* */ | |
75 /* DESCRIPTION */ | |
76 /* */ | |
77 /* This function allocates memory from the specified dynamic memory */ | |
78 /* pool. If dynamic memory is currently available, this function */ | |
79 /* is completed immediately. Otherwise, if there is not enough */ | |
80 /* memory currently available, task suspension is possible. */ | |
81 /* */ | |
82 /* CALLED BY */ | |
83 /* */ | |
84 /* Application */ | |
85 /* */ | |
86 /* CALLS */ | |
87 /* */ | |
88 /* CSC_Place_On_List Place on suspend list */ | |
89 /* [HIC_Make_History_Entry] Make entry in history log */ | |
90 /* TCC_Suspend_Task Suspend calling task */ | |
91 /* TCC_Task_Priority Pickup task priority */ | |
92 /* [TCT_Check_Stack] Stack checking function */ | |
93 /* TCT_Current_Thread Pickup current thread pointer*/ | |
94 /* TCT_Protect Protect memory pool */ | |
95 /* TCT_Set_Suspend_Protect Save suspend protection */ | |
96 /* TCT_System_Protect Protect system structures */ | |
97 /* TCT_Unprotect Release protection */ | |
98 /* TCT_Unprotect_Specific Release specific protection */ | |
99 /* */ | |
100 /* INPUTS */ | |
101 /* */ | |
102 /* pool_ptr Memory pool pointer */ | |
103 /* return_pointer Pointer to the destination */ | |
104 /* memory pointer */ | |
105 /* size Number of bytes requested */ | |
106 /* alignment Required alignment of */ | |
107 /* destination memory pointer */ | |
108 /* suspend Suspension option if full */ | |
109 /* */ | |
110 /* OUTPUTS */ | |
111 /* */ | |
112 /* NU_SUCCESS If service is successful */ | |
113 /* NU_NO_MEMORY Memory not available */ | |
114 /* NU_TIMEOUT If timeout on service */ | |
115 /* NU_POOL_DELETED If memory pool deleted */ | |
116 /* during suspension */ | |
117 /* */ | |
118 /* HISTORY */ | |
119 /* */ | |
120 /* NAME DATE REMARKS */ | |
121 /* */ | |
122 /* T. Larsen 01-15-1999 Created initial revision */ | |
123 /* R. Baum 06-06-2002 Fixed problem with DM_OVERHEAD */ | |
124 /* allocation. Added Proview */ | |
125 /* support. */ | |
126 /* */ | |
127 /*************************************************************************/ | |
128 STATUS DMS_Allocate_Aligned_Memory(NU_MEMORY_POOL *pool_ptr, | |
129 VOID **return_pointer, UNSIGNED size, | |
130 UNSIGNED alignment, UNSIGNED suspend) | |
131 { | |
132 R1 DM_PCB *pool; /* Pool control block ptr */ | |
133 R2 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */ | |
134 DM_SUSPEND suspend_block; /* Allocate suspension block */ | |
135 R4 DM_HEADER *memory_ptr; /* Pointer to memory */ | |
136 R3 DM_HEADER *new_ptr; /* New split block pointer */ | |
137 UNSIGNED free_size; /* Size of block found */ | |
138 TC_TCB *task; /* Task pointer */ | |
139 STATUS status; /* Completion status */ | |
140 UNSIGNED address; /* Address of start of block */ | |
141 UNSIGNED split_size; /* Bytes for front split */ | |
142 UNSIGNED next_aligned; /* Next aligned block addr */ | |
143 NU_SUPERV_USER_VARIABLES | |
144 | |
145 /* Switch to supervisor mode */ | |
146 NU_SUPERVISOR_MODE(); | |
147 | |
148 /* Move input pool pointer into internal pointer. */ | |
149 pool = (DM_PCB *) pool_ptr; | |
150 | |
151 | |
152 #ifdef NU_ENABLE_STACK_CHECK | |
153 | |
154 /* Call stack checking function to check for an overflow condition. */ | |
155 TCT_Check_Stack(); | |
156 | |
157 #endif | |
158 | |
159 #ifdef NU_ENABLE_HISTORY | |
160 | |
161 /* Make an entry that corresponds to this function in the system history | |
162 log. */ | |
163 HIC_Make_History_Entry(NU_ALLOCATE_ALIGNED_ID, (UNSIGNED) pool, | |
164 (UNSIGNED) return_pointer, (UNSIGNED) size); | |
165 | |
166 #endif | |
167 | |
168 /* Initialize the status as successful. */ | |
169 status = NU_SUCCESS; | |
170 | |
171 /* Adjust the request to a size evenly divisible by the number of bytes | |
172 in an UNSIGNED data element. Also, check to make sure it is of the | |
173 minimum size. */ | |
174 if (size < pool -> dm_min_allocation) | |
175 | |
176 /* Change size to the minimum allocation. */ | |
177 size = pool -> dm_min_allocation; | |
178 else | |
179 | |
180 /* Insure that size is a multiple of the UNSIGNED size. */ | |
181 size = | |
182 ((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); | |
183 | |
184 /* Adjust the requested alignment to one evenly divisible by the number of | |
185 bytes in an UNSIGNED data element. */ | |
186 alignment = | |
187 ((alignment + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); | |
188 | |
189 /* Protect against simultaneous access to the memory pool. */ | |
190 TCT_Protect(&(pool -> dm_protect)); | |
191 | |
192 /* Search the memory list for the first available block of memory that | |
193 satisfies the request. Note that blocks are merged during the | |
194 deallocation function. */ | |
195 memory_ptr = pool -> dm_search_ptr; | |
196 do | |
197 { | |
198 | |
199 /* Determine if the block is free and if it can satisfy the request. */ | |
200 if (memory_ptr -> dm_memory_free) | |
201 | |
202 /* Calculate the free block size. */ | |
203 free_size = (((BYTE_PTR) (memory_ptr -> dm_next_memory)) - | |
204 ((BYTE_PTR) memory_ptr)) - DM_OVERHEAD; | |
205 else | |
206 | |
207 /* There are no free bytes available. */ | |
208 free_size = 0; | |
209 | |
210 /* Free block may be large enough, now check alignment */ | |
211 if (free_size >= size) | |
212 { | |
213 address = ((UNSIGNED)(memory_ptr)) + DM_OVERHEAD; | |
214 | |
215 /* Is this free block, minus the overhead, already aligned? */ | |
216 if (address % alignment != 0) | |
217 { | |
218 /* Not aligned, can the free block be split in front? */ | |
219 next_aligned = address + (alignment - 1); | |
220 next_aligned /= alignment; | |
221 next_aligned *= alignment; | |
222 split_size = next_aligned - address; | |
223 | |
224 /* Is space from start of block to aligned location large enough | |
225 to contain 2 DM_OVERHEAD plus pool -> dm_min_allocation? */ | |
226 if (split_size < ((2 * DM_OVERHEAD) + pool -> dm_min_allocation)) | |
227 { | |
228 /* No, so try to make space for overhead and dm_min_allocation */ | |
229 next_aligned = address + (2 * DM_OVERHEAD) + | |
230 (pool -> dm_min_allocation) + (alignment - 1); | |
231 next_aligned /= alignment; | |
232 next_aligned *= alignment; | |
233 split_size = next_aligned - address; | |
234 } | |
235 | |
236 /* Adjust free_size for result of front split */ | |
237 if (free_size > split_size) | |
238 | |
239 free_size -= split_size; | |
240 | |
241 else | |
242 | |
243 /* Can't adjust block beginning, so keep searching */ | |
244 free_size = 0; | |
245 } | |
246 } | |
247 | |
248 /* Determine if the search should continue. */ | |
249 if (free_size < size) | |
250 | |
251 /* Large enough block has not been found. Move the search | |
252 pointer to the next block. */ | |
253 memory_ptr = memory_ptr -> dm_next_memory; | |
254 } while((free_size < size) && (memory_ptr != pool -> dm_search_ptr)); | |
255 | |
256 /* Determine if the memory is available. */ | |
257 if (free_size >= size) | |
258 { | |
259 | |
260 /* A block that satisfies the request has been found. */ | |
261 | |
262 /* Is a front split required? The front split will represent the chunk | |
263 of memory that goes from the last pointer to the aligned address. */ | |
264 if(address % alignment != 0) | |
265 { | |
266 /* Not aligned, front split the block, leaving an allocated block. */ | |
267 new_ptr = (DM_HEADER*)(((UNSIGNED)(memory_ptr)) + split_size); | |
268 | |
269 /* Mark the new block as free. */ | |
270 new_ptr -> dm_memory_free = NU_TRUE; | |
271 | |
272 /* Put the pool pointer into the new block. */ | |
273 new_ptr -> dm_memory_pool = pool; | |
274 | |
275 /* Build the necessary pointers. */ | |
276 new_ptr -> dm_previous_memory = memory_ptr; | |
277 new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; | |
278 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; | |
279 memory_ptr -> dm_next_memory = new_ptr; | |
280 | |
281 /* Decrement the available byte count by one DM_OVERHEAD. */ | |
282 pool -> dm_available = pool -> dm_available - DM_OVERHEAD; | |
283 | |
284 /* Point to new aligned free block. */ | |
285 memory_ptr = new_ptr; | |
286 } | |
287 | |
288 /* Determine if the remaining block needs to be tail split. */ | |
289 if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation)) | |
290 { | |
291 | |
292 /* Yes, split the block. */ | |
293 new_ptr = (DM_HEADER *) (((BYTE_PTR) memory_ptr) + size + | |
294 DM_OVERHEAD); | |
295 | |
296 /* Mark the new block as free. */ | |
297 new_ptr -> dm_memory_free = NU_TRUE; | |
298 | |
299 /* Put the pool pointer into the new block. */ | |
300 new_ptr -> dm_memory_pool = pool; | |
301 | |
302 /* Build the necessary pointers. */ | |
303 new_ptr -> dm_previous_memory = memory_ptr; | |
304 new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; | |
305 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; | |
306 memory_ptr -> dm_next_memory = new_ptr; | |
307 | |
308 /* Decrement the available byte count. */ | |
309 pool -> dm_available = pool -> dm_available - size - DM_OVERHEAD; | |
310 } | |
311 else | |
312 | |
313 /* Decrement the entire free size from the available bytes | |
314 count. */ | |
315 pool -> dm_available = pool -> dm_available - free_size; | |
316 | |
317 /* Mark the allocated block as not available. */ | |
318 memory_ptr -> dm_memory_free = NU_FALSE; | |
319 | |
320 /* Should the search pointer be moved? */ | |
321 if (pool -> dm_search_ptr == memory_ptr) | |
322 | |
323 /* Move the search pointer to the next free memory slot. */ | |
324 pool -> dm_search_ptr = memory_ptr -> dm_next_memory; | |
325 | |
326 /* Return a memory address to the caller. */ | |
327 *return_pointer = (VOID *) (((BYTE_PTR) memory_ptr) + DM_OVERHEAD); | |
328 #ifdef INCLUDE_PROVIEW | |
329 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_OK); | |
330 #endif /*INCLUDE_PROVIEW*/ | |
331 } | |
332 else | |
333 { | |
334 | |
335 /* Enough dynamic memory is not available. Determine if suspension is | |
336 required. */ | |
337 if (suspend) | |
338 { | |
339 | |
340 /* Suspension is selected. */ | |
341 | |
342 /* Increment the number of tasks waiting. */ | |
343 pool -> dm_tasks_waiting++; | |
344 | |
345 #ifdef INCLUDE_PROVIEW | |
346 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_WAIT); | |
347 #endif /*INCLUDE_PROVIEW*/ | |
348 /* Setup the suspend block and suspend the calling task. */ | |
349 suspend_ptr = &suspend_block; | |
350 suspend_ptr -> dm_memory_pool = pool; | |
351 suspend_ptr -> dm_request_size = size; | |
352 suspend_ptr -> dm_suspend_link.cs_next = NU_NULL; | |
353 suspend_ptr -> dm_suspend_link.cs_previous = NU_NULL; | |
354 task = (TC_TCB *) TCT_Current_Thread(); | |
355 suspend_ptr -> dm_suspended_task = task; | |
356 | |
357 /* Determine if priority or FIFO suspension is associated with the | |
358 memory pool. */ | |
359 if (pool -> dm_fifo_suspend) | |
360 { | |
361 | |
362 /* FIFO suspension is required. Link the suspend block into | |
363 the list of suspended tasks on this memory pool. */ | |
364 CSC_Place_On_List((CS_NODE **) | |
365 &(pool -> dm_suspension_list), | |
366 &(suspend_ptr -> dm_suspend_link)); | |
367 } | |
368 else | |
369 { | |
370 | |
371 /* Get the priority of the current thread so the suspend block | |
372 can be placed in the appropriate place. */ | |
373 suspend_ptr -> dm_suspend_link.cs_priority = | |
374 TCC_Task_Priority(task); | |
375 | |
376 CSC_Priority_Place_On_List((CS_NODE **) | |
377 &(pool -> dm_suspension_list), | |
378 &(suspend_ptr -> dm_suspend_link)); | |
379 } | |
380 | |
381 /* Protect against system access. */ | |
382 TCT_System_Protect(); | |
383 | |
384 /* Save the list protection in preparation for suspension. */ | |
385 TCT_Set_Suspend_Protect(&(pool -> dm_protect)); | |
386 | |
387 /* Release protection of dynamic memory pool. */ | |
388 TCT_Unprotect_Specific(&(pool -> dm_protect)); | |
389 | |
390 /* Finally, suspend the calling task. Note that the suspension call | |
391 automatically clears the system protection. */ | |
392 TCC_Suspend_Task((NU_TASK *) task, NU_MEMORY_SUSPEND, | |
393 DMC_Cleanup, suspend_ptr, suspend); | |
394 | |
395 /* Pickup the return status. */ | |
396 status = suspend_ptr -> dm_return_status; | |
397 *return_pointer = suspend_ptr -> dm_return_pointer; | |
398 } | |
399 else | |
400 { | |
401 | |
402 /* No suspension requested. Simply return an error status. */ | |
403 status = NU_NO_MEMORY; | |
404 *return_pointer = NU_NULL; | |
405 #ifdef INCLUDE_PROVIEW | |
406 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_FAIL); | |
407 #endif /*INCLUDE_PROVIEW*/ | |
408 } | |
409 } | |
410 | |
411 /* Release protection of the memory pool. */ | |
412 TCT_Unprotect(); | |
413 | |
414 /* Return to user mode */ | |
415 NU_USER_MODE(); | |
416 | |
417 /* Return the completion status. */ | |
418 return(status); | |
419 } | |
420 | |
421 | |
422 | |
423 | |
424 | |
425 |