astroboy astroboy
/
CoOS_LWIP
Quick and dirty CoOS + LWIP ( Webserver )
Diff: CoOS/kernel/kernelHeap.c
- Revision:
- 0:94897d537b31
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CoOS/kernel/kernelHeap.c Sat Sep 10 22:41:10 2011 +0000 @@ -0,0 +1,409 @@ +/** + ******************************************************************************* + * @file kernelHeap.c + * @version V1.1.4 + * @date 2011.04.20 + * @brief kernel heap management implementation code of CooCox CoOS kernel. + ******************************************************************************* + * @copy + * + * INTERNAL FILE,DON'T PUBLIC. + * + * <h2><center>© COPYRIGHT 2009 CooCox </center></h2> + ******************************************************************************* + */ + + +/*---------------------------- Include ---------------------------------------*/ +#include <coocox.h> + + +#if CFG_KHEAP_EN >0 +/*---------------------------- Variable Define -------------------------------*/ +U32 KernelHeap[KHEAP_SIZE] = {0}; /*!< Kernel heap */ +P_FMB FMBlist = Co_NULL; /*!< Free memory block list */ +KHeap Kheap = {0}; /*!< Kernel heap control */ + + +/*---------------------------- Function Declare ------------------------------*/ +static P_FMB GetPreFMB(P_UMB usedMB); +/** + ******************************************************************************* + * @brief Create kernel heap + * @param[in] None + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called to create kernel heap. + ******************************************************************************* + */ +void CoCreateKheap(void) +{ + Kheap.startAddr = (U32)(KernelHeap); /* Initialize kernel heap control */ + Kheap.endAddr = (U32)(KernelHeap) + KHEAP_SIZE*4; + FMBlist = (P_FMB)KernelHeap; /* Initialize free memory block list*/ + FMBlist->nextFMB = Co_NULL; + FMBlist->nextUMB = Co_NULL; + FMBlist->preUMB = Co_NULL; +} + + +/** + ******************************************************************************* + * @brief Allocation size bytes of memory block from kernel heap. + * @param[in] size Length of menory block. + * @param[out] None + * @retval Co_NULL Allocate fail. + * @retval others Pointer to memory block. + * + * @par Description + * @details This function is called to allocation size bytes of memory block. + ******************************************************************************* + */ +void* CoKmalloc(U32 size) +{ + P_FMB freeMB,newFMB,preFMB; + P_UMB usedMB,tmpUMB; + U8* memAddr; + U32 freeSize; + U32 kheapAddr; + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if( size == 0 ) + { + return Co_NULL; + } +#endif + + /* Word alignment,and add used memory head size */ + size = (((size+3)>>2)<<2) + 8; + kheapAddr = Kheap.endAddr; /* Get the end address of kernel heap */ + OsSchedLock(); /* Lock schedule */ + freeMB = FMBlist; /* Get first item of free memory list */ + preFMB = Co_NULL; + while(freeMB != Co_NULL ) /* Is out of free memory list? */ + { /* No */ + if(freeMB->nextUMB == Co_NULL) /* Is last item of free memory list? */ + { /* Yes,get size for this free item */ + freeSize = kheapAddr - (U32)(freeMB); + } + else /* No,get size for this free item */ + { + freeSize = (U32)(freeMB->nextUMB) -1 - (U32)(freeMB); + } + if(freeSize >= size) /* If the size equal or greater than need */ + { /* Yes,assign in this free memory */ + usedMB=(P_UMB)freeMB;/* Get the address for used memory block head*/ + + /* Get the address for used memory block */ + memAddr = (U8*)((U32)(usedMB) + 8); + + /* Is left size of free memory smaller than 12? */ + if((freeSize-size) < 12) + { + /* Yes,malloc together(12 is the size of the header information + of free memory block ). */ + if(preFMB != Co_NULL)/* Is first item of free memory block list? */ + { /* No,set the link for list */ + preFMB->nextFMB = freeMB->nextFMB; + } + else /* Yes,reset the first item */ + { + FMBlist = freeMB->nextFMB; + } + + if(freeMB->nextUMB != Co_NULL) /* Is last item? */ + { /* No,set the link for list */ + tmpUMB = (P_UMB)((U32)(freeMB->nextUMB)-1); + tmpUMB->preMB = (void*)((U32)usedMB|0x1); + } + + usedMB->nextMB = freeMB->nextUMB;/* Set used memory block link*/ + usedMB->preMB = freeMB->preUMB; + } + else /* No,the left size more than 12 */ + { + /* Get new free memory block address */ + newFMB = (P_FMB)((U32)(freeMB) + size); + + if(preFMB != Co_NULL)/* Is first item of free memory block list? */ + { + preFMB->nextFMB = newFMB; /* No,set the link for list */ + } + else + { + FMBlist = newFMB; /* Yes,reset the first item */ + } + + /* Set link for new free memory block */ + newFMB->preUMB = (P_UMB)((U32)usedMB|0x1); + newFMB->nextUMB = freeMB->nextUMB; + newFMB->nextFMB = freeMB->nextFMB; + + if(freeMB->nextUMB != Co_NULL) /* Is last item? */ + { /* No,set the link for list */ + tmpUMB = (P_UMB)((U32)(freeMB->nextUMB)-1); + tmpUMB->preMB = newFMB; + } + + usedMB->nextMB = newFMB; /* Set used memory block link */ + usedMB->preMB = freeMB->preUMB; + } + + if(freeMB->preUMB != Co_NULL) /* Is first item? */ + { /* No,set the link for list */ + tmpUMB = (P_UMB)((U32)(freeMB->preUMB)-1); + tmpUMB->nextMB = (void*)((U32)usedMB|0x1); + } + + OsSchedUnlock(); /* Unlock schedule */ + return memAddr; /* Return used memory block address */ + } + preFMB = freeMB; /* Save current free memory block as previous */ + freeMB = freeMB->nextFMB; /* Get the next item as current item*/ + } + OsSchedUnlock(); /* Unlock schedule */ + return Co_NULL; /* Error return */ +} + + +/** + ******************************************************************************* + * @brief Release memory block to kernel heap. + * @param[in] memBuf Pointer to memory block. + * @param[out] None + * @retval None + * + * @par Description + * @details This function is called to release memory block. + ******************************************************************************* + */ +void CoKfree(void* memBuf) +{ + P_FMB curFMB,nextFMB,preFMB; + P_UMB usedMB,nextUMB,preUMB; + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if(memBuf == Co_NULL) + { + return; + } +#endif + + usedMB = (P_UMB)((U32)(memBuf)-8); + +#if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ + if((U32)(memBuf) < Kheap.startAddr) + { + return; + } + if((U32)(memBuf) > Kheap.endAddr) + { + return; + } +#endif + + + OsSchedLock(); /* Lock schedule */ + +#if CFG_PAR_CHECKOUT_EN >0 /* Check UMB in list */ + if((U32)(usedMB) < (U32)(FMBlist)) + { + preUMB = (P_UMB)((U32)(FMBlist->preUMB)-1); + while(preUMB != usedMB) + { + if(preUMB == Co_NULL) + { + OsSchedUnlock(); + return; + } + preUMB = (P_UMB)((U32)(preUMB->preMB)-1); + } + } + else + { + if(FMBlist == Co_NULL) + { + nextUMB = (P_UMB)(Kheap.startAddr); + } + else + { + if(FMBlist->nextUMB != Co_NULL) + { + nextUMB = (P_UMB)((U32)(FMBlist->nextUMB)-1); + } + else + { + nextUMB = Co_NULL; + } + } + + while(nextUMB != usedMB) + { + if(nextUMB == Co_NULL) + { + OsSchedUnlock(); + return; + } + if(((U32)(nextUMB->nextMB)&0x1) == 0) + { + nextFMB = (P_FMB)(nextUMB->nextMB); + nextUMB = (P_UMB)((U32)(nextFMB->nextUMB)-1); + } + else + { + nextUMB = (P_UMB)((U32)(nextUMB->nextMB)-1); + } + } + } +#endif + + + /* Is between two free memory block? */ + if( (((U32)(usedMB->nextMB)&0x1) == 0) && (((U32)(usedMB->preMB)&0x1)==0) ) + { /* Yes,is the only one item in kernel heap? */ + if((usedMB->nextMB == Co_NULL) && (usedMB->preMB == Co_NULL)) + { + curFMB = (P_FMB)usedMB; /* Yes,release this item */ + curFMB->nextFMB = Co_NULL; + curFMB->nextUMB = Co_NULL; + curFMB->preUMB = Co_NULL; + FMBlist = curFMB; + } + else if(usedMB->preMB == Co_NULL) /* Is the first item in kernel heap */ + { + /* Yes,release this item,and set link for list */ + curFMB = (P_FMB)usedMB; + nextFMB = (P_FMB)usedMB->nextMB; + + curFMB->nextFMB = nextFMB->nextFMB; + curFMB->nextUMB = nextFMB->nextUMB; + curFMB->preUMB = Co_NULL; + FMBlist = curFMB; + } + else if(usedMB->nextMB == Co_NULL) /* Is the last item in kernel heap */ + { /* Yes,release this item,and set link for list */ + curFMB = (P_FMB)(usedMB->preMB); + curFMB->nextFMB = Co_NULL; + curFMB->nextUMB = Co_NULL; + } + else /* All no,show this item between two normal FMB */ + { + /* release this item,and set link for list */ + nextFMB = (P_FMB)usedMB->nextMB; + curFMB = (P_FMB)(usedMB->preMB); + + curFMB->nextFMB = nextFMB->nextFMB; + curFMB->nextUMB = nextFMB->nextUMB; + } + } + else if(((U32)(usedMB->preMB)&0x1) == 0) /* Is between FMB and UMB? */ + { + if(usedMB->preMB == Co_NULL) /* Yes,is the first item in kernel heap? */ + { + /* Yes,release this item,and set link for list */ + curFMB = (P_FMB)usedMB; + nextUMB = (P_UMB)usedMB->nextMB; + curFMB->nextUMB = nextUMB; + curFMB->preUMB = Co_NULL; + curFMB->nextFMB = FMBlist; + FMBlist = curFMB; + } + else /* No,release this item,and set link for list */ + { + curFMB = (P_FMB)usedMB->preMB; + nextUMB = (P_UMB)usedMB->nextMB; + curFMB->nextUMB = nextUMB; + } + + } + else if(((U32)(usedMB->nextMB)&0x1) == 0) /* Is between UMB and FMB? */ + { /* Yes */ + preUMB = (P_UMB)(usedMB->preMB); /* Get previous UMB */ + curFMB = (P_FMB)(usedMB); /* new FMB */ + preFMB = GetPreFMB(usedMB); /* Get previous FMB */ + if(preFMB == Co_NULL) /* Is previous FMB==Co_NULL? */ + { + nextFMB = FMBlist; /* Yes,get next FMB */ + FMBlist = curFMB; /* Reset new FMB as the first item of FMB list*/ + } + else + { + nextFMB = preFMB->nextFMB; /* No,get next FMB */ + preFMB->nextFMB = curFMB; /* Set link for FMB list */ + } + + if(nextFMB == Co_NULL) /* Is new FMB as last item of FMB list? */ + { + curFMB->preUMB = preUMB; /* Yes,set link for list */ + curFMB->nextUMB = Co_NULL; + curFMB->nextFMB = Co_NULL; + } + else + { + curFMB->preUMB = preUMB; /* No,set link for list */ + curFMB->nextUMB = nextFMB->nextUMB; + curFMB->nextFMB = nextFMB->nextFMB; + } + } + else /* All no,show UMB between two UMB*/ + { + curFMB = (P_FMB)(usedMB); /* new FMB */ + preFMB = GetPreFMB(usedMB); /* Get previous FMB */ + preUMB = (P_UMB)(usedMB->preMB); /* Get previous UMB */ + nextUMB = (P_UMB)(usedMB->nextMB); /* Get next UMB */ + + if(preFMB == Co_NULL ) /* Is previous FMB==Co_NULL? */ + { + nextFMB = FMBlist; /* Yes,get next FMB */ + FMBlist = curFMB; /* Reset new FMB as the first item of FMB list */ + } + else + { + nextFMB = preFMB->nextFMB; /* No,get next FMB */ + preFMB->nextFMB = curFMB; /* Set link for FMB list */ + } + + curFMB->preUMB = preUMB; /* Set current FMB link for list */ + curFMB->nextUMB = nextUMB; + curFMB->nextFMB = nextFMB; + } + + if(curFMB->preUMB != Co_NULL)/* Is current FMB as first item in kernel heap? */ + { /* No,set link for list */ + preUMB = (P_UMB)((U32)(curFMB->preUMB)-1); + preUMB->nextMB = (void*)curFMB; + } + if(curFMB->nextUMB != Co_NULL)/* Is current FMB as last item in kernel heap? */ + { /* No,set link for list */ + nextUMB = (P_UMB)((U32)(curFMB->nextUMB)-1); + nextUMB->preMB = (void*)curFMB; + } + OsSchedUnlock(); /* Unlock schedule */ +} + + +/** + ******************************************************************************* + * @brief Get previous free memory block pointer. + * @param[in] usedMB Current used memory block. + * @param[out] None + * @retval Previous free memory block pointer. + * + * @par Description + * @details This function is called to get previous free memory block pointer. + ******************************************************************************* + */ +static P_FMB GetPreFMB(P_UMB usedMB) +{ + P_UMB preUMB; + preUMB = usedMB; + while(((U32)(preUMB->preMB)&0x1)) /* Is previous MB as FMB? */ + { /* No,get previous MB */ + preUMB = (P_UMB)((U32)(preUMB->preMB)-1); + } + return (P_FMB)(preUMB->preMB); /* Yes,return previous MB */ +} + +#endif