4.2 函数LOS_RegionAlloc
函数LOS_RegionAlloc
用于从地址空间中申请空闲的虚拟地址区间。参数较多,LosVmSpace *vmSpace
指定虚拟地址空间,VADDR_T vaddr
指定虚拟地址,当为空时,从映射区申请虚拟地址;当不为空时,使用该虚拟地址。如果该虚拟地址已经被映射,会先相应的解除映射处理等。size_t len
指定要申请的地区区间的长度。UINT32 regionFlags
指定地区区间的标签。VM_OFFSET_T pgoff
指定内存页偏移值。
我们具体看下代码,⑴处如果指定的虚拟地址为空,则调用函数OsAllocRange()
申请内存。⑵如果指定的虚拟地址不为空,则调用函数OsAllocSpecificRange
申请虚拟内存,下文会详细分析这2个申请函数。⑶处创建虚拟内存地址区间,然后指定地址区间的地址空间为当前空间vmSpace
。⑷处把创建的地址区间插入地址空间的红黑树中。
LosVmMapRegion *LOS_RegionAlloc(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags, VM_OFFSET_T pgoff)
{
VADDR_T rstVaddr;
LosVmMapRegion *newRegion = NULL;
BOOL isInsertSucceed = FALSE;
/**
* If addr is NULL, then the kernel chooses the address at which to create the mapping;
* this is the most portable method of creating a new mapping. If addr is not NULL,
* then the kernel takes it as where to place the mapping;
*/
(VOID)LOS_MuxAcquire(&vmSpace->regionMux);
if (vaddr == 0) {
⑴ rstVaddr = OsAllocRange(vmSpace, len);
} else {
/* if it is already mmapped here, we unmmap it */
⑵ rstVaddr = OsAllocSpecificRange(vmSpace, vaddr, len, regionFlags);
if (rstVaddr == 0) {
VM_ERR("alloc specific range va: %#x, len: %#x failed", vaddr, len);
goto OUT;
}
}
if (rstVaddr == 0) {
goto OUT;
}
⑶ newRegion = OsCreateRegion(rstVaddr, len, regionFlags, pgoff);
if (newRegion == NULL) {
goto OUT;
}
newRegion->space = vmSpace;
⑷ isInsertSucceed = OsInsertRegion(&vmSpace->regionRbTree, newRegion);
if (isInsertSucceed == FALSE) {
(VOID)LOS_MemFree(m_aucSysMem0, newRegion);
newRegion = NULL;
}
OUT:
(VOID)LOS_MuxRelease(&vmSpace->regionMux);
return newRegion;
}
4.3 函数LOS_RegionFree
函数LOS_RegionFree
用于释放地区区间到地址空间中。⑴进行参数校验,参数不能为空。⑵处如果开启了虚拟文件系统宏,并且地址区间是有效的文件类型,则调用函数OsFilePagesRemove
。⑶处如果开启了共享内存,并且地址区间是共享的,则调用函数OsShmRegionFree
释放共享内存区间,分析共享内存部分时再详细看该函数的代码。⑷如果地址区间是设备类型的,则调用函数OsDevPagesRemove
解除映射,否则执行⑸。这些函数都涉及虚实映射,会在虚实映射章节分析这些函数。⑹处把地址区间从红黑树上移除,并释放地址区间结构体占用的内存。
STATUS_T LOS_RegionFree(LosVmSpace *space, LosVmMapRegion *region)
{
⑴ if ((space == NULL) || (region == NULL)) {
VM_ERR("args error, aspace %p, region %p", space, region);
return LOS_ERRNO_VM_INVALID_ARGS;
}
(VOID)LOS_MuxAcquire(&space->regionMux);
#ifdef LOSCFG_FS_VFS
⑵ if (LOS_IsRegionFileValid(region)) {
OsFilePagesRemove(space, region);
} else
#endif
#ifdef LOSCFG_KERNEL_SHM
⑶ if (OsIsShmRegion(region)) {
OsShmRegionFree(space, region);
} else if (LOS_IsRegionTypeDev(region)) {
#else
⑷ if (LOS_IsRegionTypeDev(region)) {
#endif
OsDevPagesRemove(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);
} else {
⑸ OsAnonPagesRemove(&space->archMmu, region->range.base, region->ran