8.阅读OSMemCreate函数及OSMemGet函数源码,特别注意其中涉及的链表操作和强制数据类型转换。
时间: 2024-03-31 11:33:12 浏览: 15
以下是针对uC/OS-II中OSMemCreate函数和OSMemGet函数的源码分析:
```c
void *OSMemCreate(void *addr, INT32U nblks, INT32U blksize, INT8U *perr)
{
OS_MEM *pmem;
INT8U *pblk;
void *p;
INT32U i;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
if (nblks < 2u) { /* Must have at least 2 blocks per list */
*perr = OS_ERR_MEM_INVALID_BLKS;
return ((void *)0);
}
if (blksize < sizeof(void *)) { /* Must be able to hold a pointer */
*perr = OS_ERR_MEM_INVALID_SIZE;
return ((void *)0);
}
#endif
OS_ENTER_CRITICAL();
pmem = OSMemFreeList; /* Get next free memory control block */
if (pmem != (OS_MEM *)0) {
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemAddr; /* Adjust free list ptr */
}
OS_EXIT_CRITICAL();
if (pmem == (OS_MEM *)0) { /* See if we have a memory block */
*perr = OS_ERR_MEM_NO_FREE_BLKS;
return ((void *)0);
}
pmem->OSMemAddr = addr; /* Save start address of memory block */
pmem->OSMemNBlks = nblks; /* Save number of blocks in the memory block */
pmem->OSMemBlkSize = blksize; /* Save size of each block */
pmem->OSMemFreeList = (void *)0;/* Block list initially empty */
pmem->OSMemNFree = 0; /* No blocks allocated initially */
pmem->OSMemTbl[0].OSMemPtr = addr;
for (i = 1; i < nblks; i++) { /* Build linked list of free blocks */
pblk = (INT8U *)pmem->OSMemTbl[i - 1].OSMemPtr;
pblk += blksize;
pmem->OSMemTbl[i].OSMemPtr = (void *)pblk;
}
pmem->OSMemTbl[nblks - 1].OSMemPtr = (void *)0; /* Last OS_MEM entry points to NULL */
OS_ENTER_CRITICAL();
pmem->OSMemFreeList = (void *)pmem->OSMemTbl[0].OSMemPtr;
p = OSMemGet(pmem, perr); /* Allocate first memory block to see if memory block is OK */
OS_EXIT_CRITICAL();
if (*perr != OS_ERR_NONE) { /* Memory block not OK, return it to free list */
pmem->OSMemAddr = (void *)0;
OSMemPut(pmem, p);
return ((void *)0);
}
OSMemPut(pmem, p); /* Free the memory block since we only needed to test memory block */
*perr = OS_ERR_NONE;
return ((void *)pmem); /* Return pointer to memory control block */
}
void *OSMemGet(OS_MEM *pmem, INT8U *perr)
{
void *pblk;
INT32U size;
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
if (pmem->OSMemNFree == 0u) { /* See if any blocks are available */
*perr = OS_ERR_MEM_NO_FREE_BLKS;
pblk = (void *)0;
} else {
pblk = pmem->OSMemFreeList; /* Get a free block from the free list */
pmem->OSMemFreeList = (void *)*((INT32U *)pblk);
pmem->OSMemNFree--; /* One less block available */
OS_EXIT_CRITICAL();
*(INT32U *)pblk = (INT32U)pmem; /* Save the memory block's ID */
pblk = (void *)((INT32U)pblk + sizeof(INT32U));
*perr = OS_ERR_NONE;
}
OS_EXIT_CRITICAL();
return (pblk);
}
```
`OSMemCreate()` 函数的作用是创建一个用于动态分配内存的内存池,并返回指向内存池的指针。该函数的参数包括内存池的起始地址、内存块的数量、每个内存块的大小以及指向错误码的指针。函数内部具体实现的步骤如下:
1. 检查传入的参数是否合法,包括内存块数量是否小于2以及每个内存块是否能够容纳一个指针。
2. 获取一个空闲的内存控制块(OS_MEM结构体),如果没有空闲的内存控制块则返回错误码。
3. 将内存池的起始地址、内存块数量、每个内存块的大小等信息保存到内存控制块中,并根据内存块数量建立一个初始为空的内存块链表。
4. 分配第一个内存块,以测试内存池是否可用。如果分配失败,则将内存池释放并返回错误码。
5. 将第一个内存块释放回内存池,并返回指向内存池的指针。
`OSMemGet()` 函数的作用是从内存池中获取一个内存块,并返回指向该内存块的指针。该函数的参数包括指向内存池的指针以及指向错误码的指针。函数内部具体实现的步骤如下:
1. 检查内存池中是否还有可用内存块,如果没有则返回错误码。
2. 从内存块链表中获取一个内存块,并将内存块从内存块链表中移除。
3. 将内存块的ID(即指向内存池的指针)保存在内存块的前四个字节中。
4. 将指向内存块的指针向后移动4个字节,以使其指向真正的内存块。
5. 返回指向内存块的指针。