转载请标明是引用于 http://blog.csdn.net/chenyujing1234
欢迎大家拍砖!
代码下载: os_mem.c 、ucos_ii.h (http://www.rayfile.com/zh-cn/files/d1e9ff6e-e517-11e1-9a2b-0015c55db73d/)
uC/OS-II的内存管理由自定义的分区(数组)来完成,根据需要进行初始化、创建、获得、释放;
注意它只是做管理,并没有提供真实使用的地址,使用的地址是通过OSMemCreate由外部提供的。
而了解这种机制,在我们平时的程序开发有多内存的应用场合,可是采用这种思想进行设备。
之前有准备好的数组OSMemTbl,然后根据要初始化的OS最大内存块数量OS_MAX_MEM_PART来初始化:
(1)如果只有一个,那么块指向第一个数组元素,指明它的OSMemName[0] = '?';
(2)如果数量有2个或以上,那么就把相应数量的数组元素的OSMemname [0] = '?';
总之,可以看出初始化只是把相应数量的数组元素的OSMenNames成员置为'?'。
void OS_MemInit (void) { #if OS_MAX_MEM_PART == 1 OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */ OSMemFreeList = (OS_MEM *)&OSMemTbl[0]; /* Point to beginning of free list */ #if OS_MEM_NAME_SIZE > 1 OSMemFreeList->OSMemName[0] = '?'; /* Unknown name */ OSMemFreeList->OSMemName[1] = OS_ASCII_NUL; #endif #endif #if OS_MAX_MEM_PART >= 2 OS_MEM *pmem; INT16U i; OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl)); /* Clear the memory partition table */ pmem = &OSMemTbl[0]; /* Point to memory control block (MCB) */ for (i = 0; i < (OS_MAX_MEM_PART - 1); i++) { /* Init. list of free memory partitions */ pmem->OSMemFreeList = (void *)&OSMemTbl[i+1]; /* Chain list of free partitions */ #if OS_MEM_NAME_SIZE > 1 pmem->OSMemName[0] = '?'; /* Unknown name */ pmem->OSMemName[1] = OS_ASCII_NUL; #endif pmem++; } pmem->OSMemFreeList = (void *)0; /* Initialize last node */ #if OS_MEM_NAME_SIZE > 1 pmem->OSMemName[0] = '?'; /* Unknown name */ pmem->OSMemName[1] = OS_ASCII_NUL; #endif OSMemFreeList = &OSMemTbl[0]; /* Point to beginning of free list */ #endif }
根据返回的OSMemFreeList指针查找下一个OSMemFreeList,看是否他为Free ,如果为Free直接返回;
如果不为Free那么根据传进来的内存开始地址、块的数量、每块的大小来初始化OSMemFreeList。
难点:
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *perr) { OS_MEM *pmem; INT8U *pblk; void **plink; INT32U i; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { /* Validate 'perr' */ return ((OS_MEM *)0); } if (addr == (void *)0) { /* Must pass a valid address for the memory part.*/ *perr = OS_ERR_MEM_INVALID_ADDR; return ((OS_MEM *)0); } if (((INT32U)addr & (sizeof(void *) - 1)) != 0){ /* Must be pointer size aligned */ *perr = OS_ERR_MEM_INVALID_ADDR; return ((OS_MEM *)0); } if (nblks < 2) { /* Must have at least 2 blocks per partition */ *perr = OS_ERR_MEM_INVALID_BLKS; return ((OS_MEM *)0); } if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */ *perr = OS_ERR_MEM_INVALID_SIZE; return ((OS_MEM *)0); } #endif OS_ENTER_CRITICAL(); pmem = OSMemFreeList; /* Get next free memory partition */ if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */ OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList; } OS_EXIT_CRITICAL(); if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */ *perr = OS_ERR_MEM_INVALID_PART; return ((OS_MEM *)0); } plink = (void **)addr; /* Create linked list of free memory blocks */ pblk = (INT8U *)((INT32U)addr + blksize); for (i = 0; i < (nblks - 1); i++) { *plink = (void *)pblk; /* Save pointer to NEXT block in CURRENT block */ plink = (void **)pblk; /* Position to NEXT block */ pblk = (INT8U *)((INT32U)pblk + blksize); /* Point to the FOLLOWING block */ } *plink = (void *)0; /* Last memory block points to NULL */ pmem->OSMemAddr = addr; /* Store start address of memory partition */ pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */ pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */ pmem->OSMemNBlks = nblks; pmem->OSMemBlkSize = blksize; /* Store block size of each memory blocks */ *perr = OS_ERR_NONE; return (pmem); }
从行参pmem中获得下一个Free的内存块,并让pmem的OSMemFreeList指针指向这块内存块。
void *OSMemGet (OS_MEM *pmem, INT8U *perr) { void *pblk; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { /* Validate 'perr' */ return ((void *)0); } if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */ *perr = OS_ERR_MEM_INVALID_PMEM; return ((void *)0); } #endif OS_ENTER_CRITICAL(); if (pmem->OSMemNFree > 0) { /* See if there are any free memory blocks */ pblk = pmem->OSMemFreeList; /* Yes, point to next free memory block */ pmem->OSMemFreeList = *(void **)pblk; /* Adjust pointer to new free list */ pmem->OSMemNFree--; /* One less memory block in this partition */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; /* No error */ return (pblk); /* Return memory block to caller */ } OS_EXIT_CRITICAL(); *perr = OS_ERR_MEM_NO_FREE_BLKS; /* No, Notify caller of empty memory partition */ return ((void *)0); /* Return NULL pointer to caller */ }
与内存的获得OSMemGet相反,这里是把释放的内存插入到控件管理块中。
INT8U OSMemPut (OS_MEM *pmem, void *pblk) { #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (pmem == (OS_MEM *)0) { /* Must point to a valid memory partition */ return (OS_ERR_MEM_INVALID_PMEM); } if (pblk == (void *)0) { /* Must release a valid block */ return (OS_ERR_MEM_INVALID_PBLK); } #endif OS_ENTER_CRITICAL(); if (pmem->OSMemNFree >= pmem->OSMemNBlks) { /* Make sure all blocks not already returned */ OS_EXIT_CRITICAL(); return (OS_ERR_MEM_FULL); } *(void **)pblk = pmem->OSMemFreeList; /* Insert released block into free block list */ pmem->OSMemFreeList = pblk; pmem->OSMemNFree++; /* One more memory block in this partition */ OS_EXIT_CRITICAL(); return (OS_ERR_NONE); /* Notify caller that memory block was released */ }