UCOS-III也使用过一段时间了,但也只是使用而已,并没有细究代码如何实现的,有时突然喜欢个刨根问底,看下所谓的内存管理到底是个什么东东,我看源代码特别是这种操作系统的源代码,总想看到不错的代码以后为自己所用,所以留下此文当作笔记。
先把代码贴进来 ,我们先来看下参数。
UCOS-III 内存管理一般是一段连续的地址(因为没有虚拟内存管理,应该在物理上也是连续的),并且起始的地址必须是对齐的即是4的倍数,每块内存大小字节数也必须是4的倍数,最小要大于4个字节。内存是你起先定义好的全局数组,也就是说内存已经被申请了,这些函数是帮助你管理这些内存,方便释放和申请,这块内存被。
p_mem 是指向内存管理结构体的指针,里面保存了管理内存的一些指针和变量(主要是内存块数目(可供使用的内存块数目),内存地址等)。
p_name 是给你创建的内存区域起名字,方便调试 ,字符指针。注意传进去的指针指向的地址应该是全局的,不可消失的。
p_addr 你全局变量数组的起始地址
n_blks 把全局变量的数组分成多少份
blk_size 每份的大小,字节单位。
总的来说,例如你事先申请个char [1024]的全局数组,然后你可以分成4份,每份大小256字节 n_blk = 4,blk_size =256;
这样你每次能申请的内存就是这4块区域的其中一块,最大使用的内存要小于256,为啥要小于256,因为有些地方保存了东西帮你维护内存,当然要占用空间了。
/*
************************************************************************************************************************
* CREATE A MEMORY PARTITION
*
* Description : Create a fixed-sized memory partition that will be managed by uC/OS-III.
*
* Arguments : p_mem is a pointer to a memory partition control block which is allocated in user memory space.
*
* p_name is a pointer to an ASCII string to provide a name to the memory partition.
*
* p_addr is the starting address of the memory partition
*
* n_blks is the number of memory blocks to create from the partition.
*
* blk_size is the size (in bytes) of each block in the memory partition.
*
* Returns : none
************************************************************************************************************************
*/
void OSMemCreate (OS_MEM *p_mem,
CPU_CHAR *p_name,
void *p_addr,
OS_MEM_QTY n_blks,
OS_MEM_SIZE blk_size,
OS_ERR *p_err)
{
#if OS_CFG_ARG_CHK_EN > 0u
CPU_DATA align_msk;
#endif
OS_MEM_QTY i;
OS_MEM_QTY loops;
CPU_INT08U *p_blk;
void **p_link;
CPU_SR_ALLOC();
//从这开始,主要是些检测参数的一些代码,和申请内存关系不大
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == DEF_TRUE) {
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
return;
}
#endif
#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
*p_err = OS_ERR_MEM_CREATE_ISR;
return;
}
#endif
#if OS_CFG_ARG_CHK_EN > 0u
if (p_addr == (void *)0) { /* Must pass a valid address for the memory part. */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if (n_blks < (OS_MEM_QTY)2) { /* Must have at least 2 blocks per partition */
*p_err = OS_ERR_MEM_INVALID_BLKS;
return;
}
if (blk_size < sizeof(void *)) { /* Must contain space for at least a pointer */
*p_err = OS_ERR_MEM_INVALID_SIZE;
return;
}
align_msk = sizeof(void *) - 1u;
if (align_msk > 0) {
if (((CPU_ADDR)p_addr & align_msk) != 0u){ /* Must be pointer size aligned */
*p_err = OS_ERR_MEM_INVALID_P_ADDR;
return;
}
if ((blk_size & align_msk) != 0u) { /* Block size must be a multiple address size */
*p_err = OS_ERR_MEM_INVALID_SIZE;
return;
}
}
#endif
//好了核心代码到了
//首先把p_addr指针转化为(void*)型指针的指针, p_link = (void **)p_addr;为啥要这么做,其实这些内存的连接靠的是指针,每块内存区域的开头保存了指向下一个
//内存的地址,*p_link 操作其实
p_link = (void **)p_addr; /* Create linked list of free memory blocks */
//把void型指针转化为unsigned char型指针,方便后面的一个字节的移位
p_blk = (CPU_INT08U *)p_addr;
loops = n_blks - 1u;
for (i = 0u; i < loops; i++) {
p_blk += blk_size;
//修改*p_link的内容, p_link的内容是什么
//*p_link 的内容和*p_addr的一样,不同点是*p_link的内容还可以作为指针使用,
//*p_addr 内容就是数据,即全局数组的前部分的值,首先p_blk是cahr型指针,*p_blk只能取一个字节
//
*p_link = (void *)p_blk; /* Save pointer to NEXT block in CURRENT block */
p_link = (void **)(void *)p_blk; /* Position to NEXT block */
}
*p_link = (void *)0; /* Last memory block points to NULL */
OS_CRITICAL_ENTER();
p_mem->Type = OS_OBJ_TYPE_MEM; /* Set the type of object */
p_mem->NamePtr = p_name; /* Save name of memory partition */
p_mem->AddrPtr = p_addr; /* Store start address of memory partition */
p_mem->FreeListPtr = p_addr; /* Initialize pointer to pool of free blocks */
p_mem->NbrFree = n_blks; /* Store number of free blocks in MCB */
p_mem->NbrMax = n_blks;
p_mem->BlkSize = blk_size; /* Store block size of each memory blocks */
#if OS_CFG_DBG_EN > 0u
OS_MemDbgListAdd(p_mem);
#endif
OSMemQty++;
OS_CRITICAL_EXIT_NO_SCHED();
*p_err = OS_ERR_NONE;
}