FreeCalypso > hg > fc-tourmaline
view src/nucleus/dms.c @ 26:598958aec071
components: switch to new Nucleus
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 17:26:36 +0000 |
parents | 4e78acac3d88 |
children |
line wrap: on
line source
/*************************************************************************/ /* */ /* Copyright Mentor Graphics Corporation 2002 */ /* All Rights Reserved. */ /* */ /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ /* SUBJECT TO LICENSE TERMS. */ /* */ /*************************************************************************/ /*************************************************************************/ /* */ /* FILE NAME VERSION */ /* */ /* dms.c Nucleus PLUS 1.14 */ /* */ /* COMPONENT */ /* */ /* DM - Dynamic Memory Management */ /* */ /* DESCRIPTION */ /* */ /* This file contains the supplemental routines for the Dynamic */ /* Memory Management component. */ /* */ /* DATA STRUCTURES */ /* */ /* None */ /* */ /* FUNCTIONS */ /* */ /* DMS_Allocate_Aligned_Memory Allocate an aligned memory */ /* block from a dynamic */ /* memory pool */ /* DEPENDENCIES */ /* */ /* cs_extr.h Common Service functions */ /* tc_extr.h Thread Control functions */ /* dm_extr.h Partition functions */ /* hi_extr.h History functions */ /* */ /* HISTORY */ /* */ /* DATE REMARKS */ /* */ /* 01-15-1999 Created initial revision */ /* 03-26-1999 Released 1.11m (new release */ /* numbering scheme) */ /* 04-17-2002 Released version 1.13m */ /* 11-07-2002 Released version 1.14 */ /*************************************************************************/ #define NU_SOURCE_FILE #include "cs_extr.h" /* Common service functions */ #include "tc_extr.h" /* Thread control functions */ #include "dm_extr.h" /* Dynamic memory functions */ #include "hi_extr.h" /* History functions */ #include "profiler.h" /* ProView interface */ /* Define external inner-component global data references. */ /* Define internal component function prototypes. */ VOID DMC_Cleanup(VOID *information); /*************************************************************************/ /* */ /* FUNCTION */ /* */ /* DMS_Allocate_Aligned_Memory */ /* */ /* DESCRIPTION */ /* */ /* This function allocates memory from the specified dynamic memory */ /* pool. If dynamic memory is currently available, this function */ /* is completed immediately. Otherwise, if there is not enough */ /* memory currently available, task suspension is possible. */ /* */ /* CALLED BY */ /* */ /* Application */ /* */ /* CALLS */ /* */ /* CSC_Place_On_List Place on suspend list */ /* [HIC_Make_History_Entry] Make entry in history log */ /* TCC_Suspend_Task Suspend calling task */ /* TCC_Task_Priority Pickup task priority */ /* [TCT_Check_Stack] Stack checking function */ /* TCT_Current_Thread Pickup current thread pointer*/ /* TCT_Protect Protect memory pool */ /* TCT_Set_Suspend_Protect Save suspend protection */ /* TCT_System_Protect Protect system structures */ /* TCT_Unprotect Release protection */ /* TCT_Unprotect_Specific Release specific protection */ /* */ /* INPUTS */ /* */ /* pool_ptr Memory pool pointer */ /* return_pointer Pointer to the destination */ /* memory pointer */ /* size Number of bytes requested */ /* alignment Required alignment of */ /* destination memory pointer */ /* suspend Suspension option if full */ /* */ /* OUTPUTS */ /* */ /* NU_SUCCESS If service is successful */ /* NU_NO_MEMORY Memory not available */ /* NU_TIMEOUT If timeout on service */ /* NU_POOL_DELETED If memory pool deleted */ /* during suspension */ /* */ /* HISTORY */ /* */ /* NAME DATE REMARKS */ /* */ /* T. Larsen 01-15-1999 Created initial revision */ /* R. Baum 06-06-2002 Fixed problem with DM_OVERHEAD */ /* allocation. Added Proview */ /* support. */ /* */ /*************************************************************************/ STATUS DMS_Allocate_Aligned_Memory(NU_MEMORY_POOL *pool_ptr, VOID **return_pointer, UNSIGNED size, UNSIGNED alignment, UNSIGNED suspend) { R1 DM_PCB *pool; /* Pool control block ptr */ R2 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */ DM_SUSPEND suspend_block; /* Allocate suspension block */ R4 DM_HEADER *memory_ptr; /* Pointer to memory */ R3 DM_HEADER *new_ptr; /* New split block pointer */ UNSIGNED free_size; /* Size of block found */ TC_TCB *task; /* Task pointer */ STATUS status; /* Completion status */ UNSIGNED address; /* Address of start of block */ UNSIGNED split_size; /* Bytes for front split */ UNSIGNED next_aligned; /* Next aligned block addr */ NU_SUPERV_USER_VARIABLES /* Switch to supervisor mode */ NU_SUPERVISOR_MODE(); /* Move input pool pointer into internal pointer. */ pool = (DM_PCB *) pool_ptr; #ifdef NU_ENABLE_STACK_CHECK /* Call stack checking function to check for an overflow condition. */ TCT_Check_Stack(); #endif #ifdef NU_ENABLE_HISTORY /* Make an entry that corresponds to this function in the system history log. */ HIC_Make_History_Entry(NU_ALLOCATE_ALIGNED_ID, (UNSIGNED) pool, (UNSIGNED) return_pointer, (UNSIGNED) size); #endif /* Initialize the status as successful. */ status = NU_SUCCESS; /* Adjust the request to a size evenly divisible by the number of bytes in an UNSIGNED data element. Also, check to make sure it is of the minimum size. */ if (size < pool -> dm_min_allocation) /* Change size to the minimum allocation. */ size = pool -> dm_min_allocation; else /* Insure that size is a multiple of the UNSIGNED size. */ size = ((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); /* Adjust the requested alignment to one evenly divisible by the number of bytes in an UNSIGNED data element. */ alignment = ((alignment + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); /* Protect against simultaneous access to the memory pool. */ TCT_Protect(&(pool -> dm_protect)); /* Search the memory list for the first available block of memory that satisfies the request. Note that blocks are merged during the deallocation function. */ memory_ptr = pool -> dm_search_ptr; do { /* Determine if the block is free and if it can satisfy the request. */ if (memory_ptr -> dm_memory_free) /* Calculate the free block size. */ free_size = (((BYTE_PTR) (memory_ptr -> dm_next_memory)) - ((BYTE_PTR) memory_ptr)) - DM_OVERHEAD; else /* There are no free bytes available. */ free_size = 0; /* Free block may be large enough, now check alignment */ if (free_size >= size) { address = ((UNSIGNED)(memory_ptr)) + DM_OVERHEAD; /* Is this free block, minus the overhead, already aligned? */ if (address % alignment != 0) { /* Not aligned, can the free block be split in front? */ next_aligned = address + (alignment - 1); next_aligned /= alignment; next_aligned *= alignment; split_size = next_aligned - address; /* Is space from start of block to aligned location large enough to contain 2 DM_OVERHEAD plus pool -> dm_min_allocation? */ if (split_size < ((2 * DM_OVERHEAD) + pool -> dm_min_allocation)) { /* No, so try to make space for overhead and dm_min_allocation */ next_aligned = address + (2 * DM_OVERHEAD) + (pool -> dm_min_allocation) + (alignment - 1); next_aligned /= alignment; next_aligned *= alignment; split_size = next_aligned - address; } /* Adjust free_size for result of front split */ if (free_size > split_size) free_size -= split_size; else /* Can't adjust block beginning, so keep searching */ free_size = 0; } } /* Determine if the search should continue. */ if (free_size < size) /* Large enough block has not been found. Move the search pointer to the next block. */ memory_ptr = memory_ptr -> dm_next_memory; } while((free_size < size) && (memory_ptr != pool -> dm_search_ptr)); /* Determine if the memory is available. */ if (free_size >= size) { /* A block that satisfies the request has been found. */ /* Is a front split required? The front split will represent the chunk of memory that goes from the last pointer to the aligned address. */ if(address % alignment != 0) { /* Not aligned, front split the block, leaving an allocated block. */ new_ptr = (DM_HEADER*)(((UNSIGNED)(memory_ptr)) + split_size); /* Mark the new block as free. */ new_ptr -> dm_memory_free = NU_TRUE; /* Put the pool pointer into the new block. */ new_ptr -> dm_memory_pool = pool; /* Build the necessary pointers. */ new_ptr -> dm_previous_memory = memory_ptr; new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; memory_ptr -> dm_next_memory = new_ptr; /* Decrement the available byte count by one DM_OVERHEAD. */ pool -> dm_available = pool -> dm_available - DM_OVERHEAD; /* Point to new aligned free block. */ memory_ptr = new_ptr; } /* Determine if the remaining block needs to be tail split. */ if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation)) { /* Yes, split the block. */ new_ptr = (DM_HEADER *) (((BYTE_PTR) memory_ptr) + size + DM_OVERHEAD); /* Mark the new block as free. */ new_ptr -> dm_memory_free = NU_TRUE; /* Put the pool pointer into the new block. */ new_ptr -> dm_memory_pool = pool; /* Build the necessary pointers. */ new_ptr -> dm_previous_memory = memory_ptr; new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; memory_ptr -> dm_next_memory = new_ptr; /* Decrement the available byte count. */ pool -> dm_available = pool -> dm_available - size - DM_OVERHEAD; } else /* Decrement the entire free size from the available bytes count. */ pool -> dm_available = pool -> dm_available - free_size; /* Mark the allocated block as not available. */ memory_ptr -> dm_memory_free = NU_FALSE; /* Should the search pointer be moved? */ if (pool -> dm_search_ptr == memory_ptr) /* Move the search pointer to the next free memory slot. */ pool -> dm_search_ptr = memory_ptr -> dm_next_memory; /* Return a memory address to the caller. */ *return_pointer = (VOID *) (((BYTE_PTR) memory_ptr) + DM_OVERHEAD); #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_OK); #endif /*INCLUDE_PROVIEW*/ } else { /* Enough dynamic memory is not available. Determine if suspension is required. */ if (suspend) { /* Suspension is selected. */ /* Increment the number of tasks waiting. */ pool -> dm_tasks_waiting++; #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_WAIT); #endif /*INCLUDE_PROVIEW*/ /* Setup the suspend block and suspend the calling task. */ suspend_ptr = &suspend_block; suspend_ptr -> dm_memory_pool = pool; suspend_ptr -> dm_request_size = size; suspend_ptr -> dm_suspend_link.cs_next = NU_NULL; suspend_ptr -> dm_suspend_link.cs_previous = NU_NULL; task = (TC_TCB *) TCT_Current_Thread(); suspend_ptr -> dm_suspended_task = task; /* Determine if priority or FIFO suspension is associated with the memory pool. */ if (pool -> dm_fifo_suspend) { /* FIFO suspension is required. Link the suspend block into the list of suspended tasks on this memory pool. */ CSC_Place_On_List((CS_NODE **) &(pool -> dm_suspension_list), &(suspend_ptr -> dm_suspend_link)); } else { /* Get the priority of the current thread so the suspend block can be placed in the appropriate place. */ suspend_ptr -> dm_suspend_link.cs_priority = TCC_Task_Priority(task); CSC_Priority_Place_On_List((CS_NODE **) &(pool -> dm_suspension_list), &(suspend_ptr -> dm_suspend_link)); } /* Protect against system access. */ TCT_System_Protect(); /* Save the list protection in preparation for suspension. */ TCT_Set_Suspend_Protect(&(pool -> dm_protect)); /* Release protection of dynamic memory pool. */ TCT_Unprotect_Specific(&(pool -> dm_protect)); /* Finally, suspend the calling task. Note that the suspension call automatically clears the system protection. */ TCC_Suspend_Task((NU_TASK *) task, NU_MEMORY_SUSPEND, DMC_Cleanup, suspend_ptr, suspend); /* Pickup the return status. */ status = suspend_ptr -> dm_return_status; *return_pointer = suspend_ptr -> dm_return_pointer; } else { /* No suspension requested. Simply return an error status. */ status = NU_NO_MEMORY; *return_pointer = NU_NULL; #ifdef INCLUDE_PROVIEW _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_FAIL); #endif /*INCLUDE_PROVIEW*/ } } /* Release protection of the memory pool. */ TCT_Unprotect(); /* Return to user mode */ NU_USER_MODE(); /* Return the completion status. */ return(status); }