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 | 
