注解用户空间/内核空间如何划分

    百图画鸿蒙 + 百文说内核 + 百万注源码  => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 99292798
......@@ -4,16 +4,16 @@
百篇博客分析|本篇为:(源码注释篇) | 每天死磕一点点
**中文注解鸿蒙内核 | [kernel_liteos_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在 `OpenHarmony`[kernel_liteos_a](https://gitee.com/openharmony/kernel_liteos_a) 基础上给内核源码加上中文注解的版本。
**中文注解鸿蒙内核 | [kernel_liteos_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在 `OpenHarmony`[kernel_liteos_a](https://gitee.com/openharmony/kernel_liteos_a) 基础上给内核源码加上中文注解的版本,同步官方代码迭代推进
### 为何要精读内核源码?
* 码农的学职生涯,都应精读一遍内核源码。以浇筑好计算机知识大厦的地基,地基纵深的坚固程度,很大程度能决定未来大厦能盖多高。那为何一定要精读细品呢?
* 因为内核代码本身并不太多,都是浓缩的精华,精读是让各个知识点高频出现,不孤立成点状记忆,没有足够连接点的知识点是很容易忘的,点点成线,线面成体,连接越多,记得越牢,如此短时间内容易结成一张高浓度,高密度的系统化知识网,训练大脑肌肉记忆,驻入大脑直觉区,想抹都抹不掉,终生携带,随时调取。跟骑单车一样,一旦学会,即便多年不骑,照样跨上就走,游刃有余。
### 热爱是所有的理由和答案
* 因大学时阅读 `linux 2.6` 内核痛并快乐的经历,一直有个心愿,如何让更多对内核感兴趣的朋友减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃。但因过程种种,多年一直没有行动,基本要放弃这件事了。恰逢 `2020/9/10` 鸿蒙正式开源,重新激活了多年的心愿,就有那么点如黄河之水一发不可收拾了。
* 目前对内核源码的注解完成 `80%` ,博客分析完成`70+篇`,百图画鸿蒙完成`20张`所有空闲时间几乎被占用,每天很充实,时间不够用,连做梦内核代码都在鱼贯而入。加注并整理是件很有挑战的事,时间单位上以年计,已持续快一年半,不觉疲怠,期间得到众多小伙伴的支持与鼓励,让此念越发强烈,坚如磐石,干困难事,方有所得;专注聚焦,必有所获。做有兴趣有意思的事并不觉得有多难 :P
* 目前对内核源码的注解完成 `80%` ,博客分析完成`70+篇`,百图画鸿蒙完成`20张`空闲时间几乎被占用,每天很充实,时间不够用,连做梦内核代码都在鱼贯而入。加注并整理是件很有挑战的事,时间单位上以年计,已持续一年半,期间得到众多小伙伴的支持与纠错,让此念越发强烈,坚如磐石。:P
### (〃・ิ‿・ิ)ゞ鸿蒙内核开发者
* 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此。从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的。可以毫不夸张的说鸿蒙内核源码可作为大学:C语言,数据结构,操作系统,汇编语言,计算机系统结构,计算机组成原理 六门课程的教学项目。如此宝库,不深入研究实在是暴殄天物,于心不忍,注者坚信鸿蒙大势所趋,未来可期,其必定成功,也必然成功,誓做其坚定的追随者和传播者。
* 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此。从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的。可以毫不夸张的说鸿蒙内核源码可作为大学:C语言,数据结构,操作系统,汇编语言,计算机系统结构,计算机组成原理,微机接口 七门课程的教学项目。如此宝库,不深入研究实在是暴殄天物,于心不忍,坚信鸿蒙大势所趋,未来可期,其必定成功,也必然成功,誓做其坚定的追随者和传播者。
### 理解内核的三个层级
......@@ -114,6 +114,7 @@
* [v73.01 鸿蒙内核源码分析(参考文档) | 阅读内核源码必备工具](https://my.oschina.net/weharmony/blog/5346868)
* [v74.01 鸿蒙内核源码分析(控制台) | 一个让很多人模糊的概念](https://my.oschina.net/weharmony/blog/5356308)
* [v75.01 鸿蒙内核源码分析(远程登录) | 内核如何接待远方的客人](https://my.oschina.net/weharmony/blog/5375838)
* [v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式](https://my.oschina.net/weharmony/blog/5412148)
#### 三: 百万注内核 | 处处扣细节 | 细胞血管
* 百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。
......@@ -188,4 +189,5 @@
### 关注不迷路 | 代码即人生
![](https://gitee.com/weharmonyos/resources/raw/master/common/so1so.png)
\ No newline at end of file
![](https://gitee.com/weharmonyos/resources/raw/master/common/so1so.png)
......@@ -146,7 +146,7 @@ typedef struct VmSpace {
LOS_DL_LIST node; /**< vm space dl list | 节点,通过它挂到全局虚拟空间 g_vmSpaceList 链表上*/
LosRbTree regionRbTree; /**< region red-black tree root | 采用红黑树方式管理本空间各个线性区*/
LosMux regionMux; /**< region list mutex lock | 虚拟空间的互斥锁*/
VADDR_T base; /**< vm space base addr | 虚拟空间的基地址,常用于判断地址是否在内核还是用户空间*/
VADDR_T base; /**< vm space base addr | 虚拟空间的基地址,线性区的分配范围,常用于判断地址是否在内核还是用户空间*/
UINT32 size; /**< vm space size | 虚拟空间大小*/
VADDR_T heapBase; /**< vm space heap base address | 堆区基地址,表堆区范围起点*/
VADDR_T heapNow; /**< vm space heap base now | 堆区现地址,表堆区范围终点,do_brk()直接修改堆的大小返回新的堆区结束地址, heapNow >= heapBase*/
......@@ -172,10 +172,10 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_STRONGLY_ORDERED (3<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0) ///< 缓冲区掩码
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) ///< 用户空间区
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3) ///< 可读取区
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) ///< 可写入区
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) ///< 可被执行区
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) ///< 用户空间永久区,PERM表示常驻区,可理解为非栈,非堆
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3) ///< 永久可读取区
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) ///< 永久可写入区
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) ///< 永久可被执行区
#define VM_MAP_REGION_FLAG_PROT_MASK (0xF<<2) ///< 访问权限掩码
#define VM_MAP_REGION_FLAG_NS (1<<6) /* NON-SECURE */
#define VM_MAP_REGION_FLAG_SHARED (1<<7) ///< MAP_SHARED:把对该内存段的修改保存到磁盘文件中 详见 OsCvtProtFlagsToRegionFlags ,要和 VM_MAP_REGION_FLAG_SHM区别理解
......@@ -185,19 +185,19 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_HEAP (1<<10) ///< 线性区的类型:堆区
#define VM_MAP_REGION_FLAG_DATA (1<<11) ///< data数据区 编译在ELF中
#define VM_MAP_REGION_FLAG_TEXT (1<<12) ///< 代码区
#define VM_MAP_REGION_FLAG_BSS (1<<13) ///< bbs数据区 由运行时动态分配
#define VM_MAP_REGION_FLAG_BSS (1<<13) ///< bbs数据区 由运行时动态分配,bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
#define VM_MAP_REGION_FLAG_VDSO (1<<14) ///< VDSO(Virtual Dynamic Shared Object,虚拟动态共享库)由内核提供的虚拟.so文件,它不在磁盘上,而在内核里,内核将其映射到一个地址空间中,被所有程序共享,正文段大小为一个页面。
#define VM_MAP_REGION_FLAG_MMAP (1<<15) ///< 映射区,虚拟空间内有专门用来存储<虚拟地址-物理地址>映射的区域
#define VM_MAP_REGION_FLAG_SHM (1<<16) ///< 共享内存区,和代码区同级概念,意思是整个线性区被贴上共享标签
#define VM_MAP_REGION_FLAG_FIXED (1<<17)
#define VM_MAP_REGION_FLAG_FIXED_NOREPLACE (1<<18)
#define VM_MAP_REGION_FLAG_FIXED (1<<17) ///< 填满线性区
#define VM_MAP_REGION_FLAG_FIXED_NOREPLACE (1<<18) ///<
#define VM_MAP_REGION_FLAG_INVALID (1<<19) /* indicates that flags are not specified */
/// 从外部权限标签转化为线性区权限标签
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
{
UINT32 regionFlags = 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须是可用
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER; //必须是用户空间
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0; //映射区可被读
regionFlags |= (prot & PROT_WRITE) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE) : 0;
regionFlags |= (prot & PROT_EXEC) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE) : 0;
......@@ -234,7 +234,7 @@ STATIC INLINE BOOL LOS_IsRegionTypeFile(LosVmMapRegion* region)
{
return region->regionType == VM_MAP_REGION_TYPE_FILE;
}
/// permanent 用户进程常量
/// permanent 用户进程永久/常驻
STATIC INLINE BOOL LOS_IsRegionPermUserReadOnly(LosVmMapRegion* region)
{
return ((region->regionFlags & VM_MAP_REGION_FLAG_PROT_MASK) ==
......
......@@ -223,7 +223,7 @@ VOID OsVmMapInit(VOID)
///初始化内核虚拟空间
BOOL OsKernVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//内核空间页表是编译时放在bbs段指定的,共用 L1表
{
vmSpace->base = KERNEL_ASPACE_BASE;//内核空间基地址
vmSpace->base = KERNEL_ASPACE_BASE;//内核空间基地址, 线性区将分配在此范围
vmSpace->size = KERNEL_ASPACE_SIZE;//内核空间大小
vmSpace->mapBase = KERNEL_VMM_BASE;//内核空间映射区基地址
vmSpace->mapSize = KERNEL_VMM_SIZE;//内核空间映射区大小
......@@ -439,7 +439,7 @@ VADDR_T OsAllocRange(LosVmSpace *vmSpace, size_t len)
LosRbNode *pstRbNode = NULL;
LosRbNode *pstRbNodeTmp = NULL;
LosRbTree *regionRbTree = &vmSpace->regionRbTree;
VADDR_T curEnd = vmSpace->mapBase;
VADDR_T curEnd = vmSpace->mapBase;//获取映射区基地址
VADDR_T nextStart;
curRegion = LOS_RegionFind(vmSpace, vmSpace->mapBase);
......@@ -486,23 +486,23 @@ VADDR_T OsAllocSpecificRange(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UIN
{
STATUS_T status;
if (LOS_IsRangeInSpace(vmSpace, vaddr, len) == FALSE) {
if (LOS_IsRangeInSpace(vmSpace, vaddr, len) == FALSE) {//虚拟地址是否在进程空间范围内
return 0;
}
if ((LOS_RegionFind(vmSpace, vaddr) != NULL) ||
(LOS_RegionFind(vmSpace, vaddr + len - 1) != NULL) ||
(LOS_RegionRangeFind(vmSpace, vaddr, len - 1) != NULL)) {
(LOS_RegionRangeFind(vmSpace, vaddr, len - 1) != NULL)) {//没找到的情况
if ((regionFlags & VM_MAP_REGION_FLAG_FIXED_NOREPLACE) != 0) {
return 0;
} else if ((regionFlags & VM_MAP_REGION_FLAG_FIXED) != 0) {
status = LOS_UnMMap(vaddr, len);
} else if ((regionFlags & VM_MAP_REGION_FLAG_FIXED) != 0) {//线性区未填满,则解除这部分空间的映射
status = LOS_UnMMap(vaddr, len);//解除映射
if (status != LOS_OK) {
VM_ERR("unmap specific range va: %#x, len: %#x failed, status: %d", vaddr, len, status);
return 0;
}
} else {
return OsAllocRange(vmSpace, len);
return OsAllocRange(vmSpace, len);//默认分配一个
}
}
......@@ -589,11 +589,11 @@ LosVmMapRegion *LOS_RegionAlloc(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len,
* then the kernel takes it as where to place the mapping;
*/
(VOID)LOS_MuxAcquire(&vmSpace->regionMux);//获得互斥锁
if (vaddr == 0) {//如果地址是0,则由内核选择创建映射的虚拟地址, 这是创建新映射的最便捷的方法。
if (vaddr == 0) {//如果地址是0,根据线性区管理的实际情况,自动创建虚拟地址, 这是创建新映射的最便捷的方法。
rstVaddr = OsAllocRange(vmSpace, len);
} else {
/* if it is already mmapped here, we unmmap it */
rstVaddr = OsAllocSpecificRange(vmSpace, vaddr, len, regionFlags);
rstVaddr = OsAllocSpecificRange(vmSpace, vaddr, len, regionFlags);//创建包含指定虚拟地址的线性区, rstVaddr != vaddr || rstVaddr == vaddr
if (rstVaddr == 0) {
VM_ERR("alloc specific range va: %#x, len: %#x failed", vaddr, len);
goto OUT;
......@@ -603,7 +603,7 @@ LosVmMapRegion *LOS_RegionAlloc(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len,
goto OUT;
}
newRegion = OsCreateRegion(rstVaddr, len, regionFlags, pgoff);//从内存池中创建一个线性区
newRegion = OsCreateRegion(rstVaddr, len, regionFlags, pgoff);//创建一个线性区,指定线性区的开始地址rstVaddr ...
if (newRegion == NULL) {
goto OUT;
}
......@@ -1094,9 +1094,9 @@ STATUS_T LOS_VaddrToPaddrMmap(LosVmSpace *space, VADDR_T vaddr, PADDR_T paddr, s
}
//对外接口|申请内核堆空间内存
VOID *LOS_VMalloc(size_t size)//从g_vMallocSpace中申请物理内存
VOID *LOS_VMalloc(size_t size)
{
LosVmSpace *space = &g_vMallocSpace;
LosVmSpace *space = &g_vMallocSpace;//从内核动态空间申请
LosVmMapRegion *region = NULL;
size_t sizeCount;
size_t count;
......
......@@ -188,6 +188,7 @@ LITE_OS_SEC_TEXT STATIC BOOL IsPoolMapped(ProcIpcInfo *ipcInfo)
/*!
* @brief DoIpcMmap
* 做IPC层映射,将内核空间虚拟地址映射到用户空间,这样的好处是用户态下操作读写的背后是在读写内核态空间
* 如此用户地址和内核地址指向同一个物理地址
* @param pcb
* @param region
* @return
......@@ -206,7 +207,7 @@ LITE_OS_SEC_TEXT STATIC INT32 DoIpcMmap(LosProcessCB *pcb, LosVmMapRegion *regio
(VOID)LOS_MuxAcquire(&pcb->vmSpace->regionMux);
for (i = 0; i < (region->range.size >> PAGE_SHIFT); i++) {//获取线性区页数
for (i = 0; i < (region->range.size >> PAGE_SHIFT); i++) {//获取线性区页数,一页一页映射
pa = LOS_PaddrQuery((VOID *)(UINTPTR)(kva + (i << PAGE_SHIFT)));//通过内核空间查找物理地址
if (pa == 0) {
PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
......@@ -226,7 +227,7 @@ LITE_OS_SEC_TEXT STATIC INT32 DoIpcMmap(LosProcessCB *pcb, LosVmMapRegion *regio
break;
}
}
/* if any failure happened, rollback | 如果发生失败,则回滚*/
/* if any failure happened, rollback | 如果中间发生映射失败,则回滚*/
if (i != (region->range.size >> PAGE_SHIFT)) {
while (i--) {
pa = LOS_PaddrQuery((VOID *)(UINTPTR)(kva + (i << PAGE_SHIFT)));//查询物理地址
......@@ -246,7 +247,7 @@ LITE_OS_SEC_TEXT STATIC int LiteIpcMmap(struct file *filep, LosVmMapRegion *regi
LosVmMapRegion *regionTemp = NULL;
LosProcessCB *pcb = OsCurrProcessGet();
ProcIpcInfo *ipcInfo = pcb->ipcInfo;
//被映射的线性区不能在常量和私有数据区
if ((ipcInfo == NULL) || (region == NULL) || (region->range.size > LITE_IPC_POOL_MAX_SIZE) ||
(!LOS_IsRegionPermUserReadOnly(region)) || (!LOS_IsRegionFlagPrivateOnly(region))) {
ret = -EINVAL;
......@@ -256,20 +257,21 @@ LITE_OS_SEC_TEXT STATIC int LiteIpcMmap(struct file *filep, LosVmMapRegion *regi
return -EEXIST;
}
if (ipcInfo->pool.uvaddr != NULL) {//ipc池已在进程空间有地址
regionTemp = LOS_RegionFind(pcb->vmSpace, (VADDR_T)(UINTPTR)ipcInfo->pool.uvaddr);//找到所在线性区
regionTemp = LOS_RegionFind(pcb->vmSpace, (VADDR_T)(UINTPTR)ipcInfo->pool.uvaddr);//在指定进程空间中找到所在线性区
if (regionTemp != NULL) {
(VOID)LOS_RegionFree(pcb->vmSpace, regionTemp);//先释放线性区
}
// 建议加上 ipcInfo->pool.uvaddr = NULL; 同下
}
ipcInfo->pool.uvaddr = (VOID *)(UINTPTR)region->range.base;//将指定的线性区和ipc池虚拟地址绑定
if (ipcInfo->pool.kvaddr != NULL) {//如果
LOS_VFree(ipcInfo->pool.kvaddr);
ipcInfo->pool.kvaddr = NULL;
if (ipcInfo->pool.kvaddr != NULL) {//如果存在内核空间地址
LOS_VFree(ipcInfo->pool.kvaddr);//因为要重新映射,所以必须先释放掉物理内存
ipcInfo->pool.kvaddr = NULL; //从效果上看, 这句话可以不加,但加上看着更舒服, uvaddr 和 kvaddr 一对新人迎接美好未来
}
/* use vmalloc to alloc phy mem */
ipcInfo->pool.kvaddr = LOS_VMalloc(region->range.size);//分配物理内存
if (ipcInfo->pool.kvaddr == NULL) {
ret = -ENOMEM;
ipcInfo->pool.kvaddr = LOS_VMalloc(region->range.size);//从内核动态空间中申请线性区,分配同等量的物理内存,做好 内核 <-->物理内存的映射
if (ipcInfo->pool.kvaddr == NULL) {//申请物理内存失败, 肯定是玩不下去了.
ret = -ENOMEM; //返回没有内存了
goto ERROR_REGION_OUT;
}
/* do mmap */
......@@ -472,7 +474,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckUsedBuffer(const VOID *node, IpcListNode **o
/// 获取任务ID
LITE_OS_SEC_TEXT STATIC UINT32 GetTid(UINT32 serviceHandle, UINT32 *taskID)
{
if (serviceHandle >= MAX_SERVICE_NUM) {
if (serviceHandle >= MAX_SERVICE_NUM) {//超过任务数
return -EINVAL;
}
(VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
......@@ -577,11 +579,11 @@ LITE_OS_SEC_TEXT STATIC BOOL HasServiceAccess(UINT32 serviceHandle)
return TRUE;
}
if (OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo == NULL) {
if (OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo == NULL) {//如果参数任务没有开通处理IPC信息功能
return FALSE;
}
return OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo->accessMap[curProcessID];
return OS_TCB_FROM_TID(serviceTid)->ipcTaskInfo->accessMap[curProcessID];//返回任务访问进程的权限
}
///设置ipc任务ID
LITE_OS_SEC_TEXT STATIC UINT32 SetIpcTask(VOID)
......@@ -610,14 +612,14 @@ LITE_OS_SEC_TEXT STATIC UINT32 GetIpcTaskID(UINT32 processID, UINT32 *ipcTaskID)
*ipcTaskID = OS_PCB_FROM_PID(processID)->ipcInfo->ipcTaskID;
return LOS_OK;
}
/// 发送死亡消息
/// serviceHandle 给 processID 发送死亡/结束消息, serviceHandle 为 taskID
LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHandle)
{
UINT32 ipcTaskID;
UINT32 ret;
IpcContent content;
IpcMsg msg;
LosProcessCB *pcb = OS_PCB_FROM_PID(processID);
LosProcessCB *pcb = OS_PCB_FROM_PID(processID);//获取指定进程控制块
if (pcb->ipcInfo == NULL) {
return -EINVAL;
......@@ -625,7 +627,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 SendDeathMsg(UINT32 processID, UINT32 serviceHand
pcb->ipcInfo->access[serviceHandle] = FALSE;
ret = GetIpcTaskID(processID, &ipcTaskID);
ret = GetIpcTaskID(processID, &ipcTaskID);//获取操作该进程IPC的任务ID, processID 下的某个 taskID
if (ret != LOS_OK) {
return -EINVAL;
}
......@@ -648,7 +650,7 @@ LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle(UINT32 taskID)
return;
}
#if (USE_TASKID_AS_HANDLE == 1)
#if (USE_TASKID_AS_HANDLE == 1) // 任务ID当做句柄使用
UINT32 intSave;
LOS_DL_LIST *listHead = NULL;
......@@ -656,19 +658,19 @@ LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle(UINT32 taskID)
IpcListNode *node = NULL;
UINT32 processID = taskCB->processID;
listHead = &(ipcTaskInfo->msgListHead);
do {
listHead = &(ipcTaskInfo->msgListHead);// ipc 节点链表
do {// 循环删除 任务IPC上挂的各个节点
SCHEDULER_LOCK(intSave);
if (LOS_ListEmpty(listHead)) {
if (LOS_ListEmpty(listHead)) {//空判
SCHEDULER_UNLOCK(intSave);
break;
} else {
listNode = LOS_DL_LIST_FIRST(listHead);
LOS_ListDelete(listNode);
node = LOS_DL_LIST_ENTRY(listNode, IpcListNode, listNode);
listNode = LOS_DL_LIST_FIRST(listHead); //拿到首个节点
LOS_ListDelete(listNode); //删除节点
node = LOS_DL_LIST_ENTRY(listNode, IpcListNode, listNode);//获取节点所在结构体 IpcListNode
SCHEDULER_UNLOCK(intSave);
(VOID)HandleSpecialObjects(taskCB->taskID, node, TRUE);
(VOID)LiteIpcNodeFree(processID, (VOID *)node);
(VOID)HandleSpecialObjects(taskCB->taskID, node, TRUE);//处理节点
(VOID)LiteIpcNodeFree(processID, (VOID *)node);//释放节点占用的进程空间
}
} while (1);
......@@ -676,10 +678,10 @@ LITE_OS_SEC_TEXT VOID LiteIpcRemoveServiceHandle(UINT32 taskID)
for (j = 0; j < MAX_SERVICE_NUM; j++) {
if (ipcTaskInfo->accessMap[j] == TRUE) {
ipcTaskInfo->accessMap[j] = FALSE;
(VOID)SendDeathMsg(j, taskCB->taskID);
(VOID)SendDeathMsg(j, taskCB->taskID); //给进程发送taskCB死亡的消息
}
}
#else
#else
(VOID)LOS_MuxLock(&g_serviceHandleMapMux, LOS_WAIT_FOREVER);
for (UINT32 i = 1; i < MAX_SERVICE_NUM; i++) {
if ((g_serviceHandleMap[i].status != HANDLE_NOT_USED) && (g_serviceHandleMap[i].taskID == taskCB->taskID)) {
......@@ -862,7 +864,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 HandleObj(UINT32 dstTid, SpecialObj *obj, BOOL is
}
return ret;
}
//处理指定任务的某个IPC节点
LITE_OS_SEC_TEXT STATIC UINT32 HandleSpecialObjects(UINT32 dstTid, IpcListNode *node, BOOL isRollback)
{
UINT32 ret = LOS_OK;
......@@ -901,7 +903,7 @@ EXIT:
}
return ret;
}
/// 检查消息内容大小
LITE_OS_SEC_TEXT STATIC UINT32 CheckMsgSize(IpcMsg *msg)
{
UINT64 totalSize;
......@@ -936,7 +938,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckMsgSize(IpcMsg *msg)
(VOID)LOS_MuxUnlock(&g_serviceHandleMapMux);
return LOS_OK;
}
///< 从用户空间拷贝数据
LITE_OS_SEC_TEXT STATIC UINT32 CopyDataFromUser(IpcListNode *node, UINT32 bufSz, const IpcMsg *msg)
{
UINT32 ret;
......@@ -999,7 +1001,7 @@ LITE_OS_SEC_TEXT STATIC BOOL IsValidReply(const IpcContent *content)
}
return TRUE;
}
/// 检查参数,并获取目标 任务ID
LITE_OS_SEC_TEXT STATIC UINT32 CheckPara(IpcContent *content, UINT32 *dstTid)
{
UINT32 ret;
......@@ -1015,9 +1017,9 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckPara(IpcContent *content, UINT32 *dstTid)
(msg->dataSz < msg->spObjNum * sizeof(SpecialObj))) {
return -EINVAL;
}
switch (msg->type) {
case MT_REQUEST:
if (HasServiceAccess(msg->target.handle)) {
switch (msg->type) {//消息类型
case MT_REQUEST: //请求
if (HasServiceAccess(msg->target.handle)) {//检查参数任务是否有权限访问当前进程
ret = GetTid(msg->target.handle, dstTid);
if (ret != LOS_OK) {
return -EINVAL;
......@@ -1030,8 +1032,8 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckPara(IpcContent *content, UINT32 *dstTid)
msg->timestamp = now;
#endif
break;
case MT_REPLY:
case MT_FAILED_REPLY:
case MT_REPLY://回复
case MT_FAILED_REPLY: //回复失败消息
if ((flag & BUFF_FREE) != BUFF_FREE) {
return -EINVAL;
}
......@@ -1054,7 +1056,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 CheckPara(IpcContent *content, UINT32 *dstTid)
#endif
*dstTid = msg->target.handle;
break;
case MT_DEATH_NOTIFY:
case MT_DEATH_NOTIFY://死亡消息
*dstTid = msg->target.handle;
#if (USE_TIMESTAMP == 1)
msg->timestamp = now;
......@@ -1235,7 +1237,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcRead(IpcContent *content)
EnableIpcNodeFreeByUser(LOS_GetCurrProcessID(), (VOID *)node);
return LOS_OK;
}
/// 处理 IPC 消息
LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle(IpcContent *con)
{
UINT32 ret = LOS_OK;
......@@ -1250,7 +1252,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle(IpcContent *con)
return -EINVAL;
}
if ((content->flag & BUFF_FREE) == BUFF_FREE) {
if ((content->flag & BUFF_FREE) == BUFF_FREE) { // 空闲
ret = CheckUsedBuffer(content->buffToFree, &nodeNeedFree);
if (ret != LOS_OK) {
PRINT_ERR("CheckUsedBuffer failed:%d\n", ret);
......@@ -1258,18 +1260,18 @@ LITE_OS_SEC_TEXT STATIC UINT32 LiteIpcMsgHandle(IpcContent *con)
}
}
if ((content->flag & SEND) == SEND) {
if ((content->flag & SEND) == SEND) { // 向外发送
if (content->outMsg == NULL) {
PRINT_ERR("content->outmsg is null\n");
ret = -EINVAL;
goto BUFFER_FREE;
}
}// 1. 先将用户空间过来的消息拷贝到内核空间 (先拷贝壳)
if (copy_from_user((void *)msg, (const void *)content->outMsg, sizeof(IpcMsg)) != LOS_OK) {
PRINT_ERR("%s, %d\n", __FUNCTION__, __LINE__);
ret = -EINVAL;
goto BUFFER_FREE;
}
content->outMsg = msg;
content->outMsg = msg;// outMsg 指向内核空间
if ((content->outMsg->type < 0) || (content->outMsg->type >= MT_DEATH_NOTIFY)) {
PRINT_ERR("LiteIpc unknow msg type:%d\n", content->outMsg->type);
ret = -EINVAL;
......@@ -1290,7 +1292,7 @@ BUFFER_FREE:
return ret;
}
if ((content->flag & RECV) == RECV) {
if ((content->flag & RECV) == RECV) {//接收到消息
ret = LiteIpcRead(content);
if (ret != LOS_OK) {
PRINT_ERR("LiteIpcRead failed ERROR: %d\n", (INT32)ret);
......
......@@ -91,7 +91,7 @@ typedef struct {
*/
typedef struct {
IpcPool pool; ///< ipc池
UINT32 ipcTaskID; ///< 当前由哪个任务ID在操作进程的IPC 通过 SetIpcTask 操作
UINT32 ipcTaskID; ///< 当前由哪个任务在操作进程的IPC 通过 SetIpcTask 操作
LOS_DL_LIST ipcUsedNodelist;///< 已使用节点链表
UINT32 access[LOSCFG_BASE_CORE_TSK_LIMIT]; ///< 允许进程通过IPC访问哪些任务
} ProcIpcInfo;
......@@ -174,10 +174,10 @@ typedef struct {//IPC 消息结构体
#endif
UINT32 dataSz; /**< size of data | 消息内容大小*/
VOID *data; ///< 消息的内容,真正要传递的消息
UINT32 spObjNum; // ..
VOID *offsets; // ..
UINT32 processID; /**< filled by kernel, processId of sender/reciever | 由内核填充,发送/接收消息的进程ID*/
UINT32 taskID; /**< filled by kernel, taskId of sender/reciever | 由内核填充,发送/接收消息的任务ID*/
UINT32 spObjNum; ///< 对象数量
VOID *offsets; ///< 偏移量
UINT32 processID; /**< filled by kernel, processId of sender/reciever | 由内核提供,发送/接收消息的进程ID*/
UINT32 taskID; /**< filled by kernel, taskId of sender/reciever | 由内核提供,发送/接收消息的任务ID*/
#ifdef LOSCFG_SECURITY_CAPABILITY
UINT32 userID; ///< 用户ID
UINT32 gid; ///< 组ID
......@@ -198,7 +198,7 @@ typedef struct { //IPC 内容节点
*/
typedef struct {
UINT32 flag; /**< size of writeData | IPC标签 (SEND,RECV,BUFF_FREE)*/
IpcMsg *outMsg; /**< data to send to target | 发给目标任务的消息内容*/
IpcMsg *outMsg; /**< data to send to target | 发给目标任务的消息内容*/
IpcMsg *inMsg; /**< data reply by target | 目标任务回复的消息内容*/
VOID *buffToFree;
} IpcContent;
......
git add -A
git commit -m ' LiteIPC 注释完善, 它内核提供的一种新型IPC通讯机制
git commit -m ' 注解用户空间/内核空间如何划分
百图画鸿蒙 + 百文说内核 + 百万注源码 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册