
v78.01 鸿蒙内核源码分析(消息映射篇)|剖析LiteIpc(下)通讯机制 原创 精华
百篇博客分析|本篇为:(消息映射篇) | 剖析LiteIpc(下)进程通讯机制
进程通讯相关篇为:
- v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志
- v27.05 鸿蒙内核源码分析(互斥锁) | 同样是锁它确更丰满
- v28.04 鸿蒙内核源码分析(进程通讯) | 九种进程间通讯方式速揽
- v29.05 鸿蒙内核源码分析(信号量) | 谁在解决任务间的同步
- v30.07 鸿蒙内核源码分析(事件控制) | 多对多任务如何同步
- v33.03 鸿蒙内核源码分析(消息队列) | 进程间如何异步传递大数据
- v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式
- v77.02 鸿蒙内核源码分析(消息封装) | 剖析LiteIpc(上)进程通讯内容
- v78.01 鸿蒙内核源码分析(消息映射) | 剖析LiteIpc(下)进程通讯机制
基本概念
LiteIPC
是OpenHarmony LiteOS-A
内核提供的一种新型IPC
(Inter-Process Communication,即进程间通信)机制,为轻量级进程间通信组件,为面向服务的系统服务框架提供进程间通信能力,分为内核实现和用户态实现两部分,其中内核实现完成进程间消息收发、IPC内存管理、超时通知和死亡通知等功能;用户态提供序列化和反序列化能力,并完成IPC
回调消息和死亡消息的分发。
我们主要讲解内核态实现部分,本想一篇说完,但发现它远比想象中的复杂和重要,所以分通讯内容和通讯机制上下两篇说。上篇可翻看 鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc(上)进程通讯内容 ,本篇为通讯机制,介绍liteipc在内核层的实现过程。
空间映射
映射 一词在系列篇中多次出现,虚拟地址的基础就是映射,共享内存的实现也要靠映射,LiteIPC
通讯的底层实现也离不开映射,有意思的是将用户态的线性区和内核态的线性区进行了映射。也就是说当用户访问用户空间中的某个虚拟地址时,其实和内核空间某个虚拟地址都指向了同一个物理内存地址。可能有人会问这也行 ? 在了解完物理地址,内核虚地址,用户虚地址之间的关系后就会明白这当然可以。
-
虚拟地址包括内核空间地址和用户进程空间地址,它们的范围对外暴露,由系统集成商设定,内核也专门提供了判断函数。即看到一个虚拟地址可以知道是内核在用还是用户(应用)进程在用。
-
物理地址是由物理内存提供,系统集成商根据实际的物理内存大小来设定地址范围。至于具体的某段物理内存是给内核空间还是给用户空间使用并没有要求,所谓映射是指虚拟地址 <–> 物理地址的映射,是 N:1的关系,一个物理地址可以被多个虚拟地址映射,而一个虚拟地址只能映射到一个物理地址。
-
以上是
LiteIPC
的实现概念基础,明白后就不难理解结构体IpcPool
存在的意义了
文件访问
LiteIPC
的运行机制是首先将需要接收IPC
消息的任务通过ServiceManager
注册成为一个Service
,然后通过ServiceManager
为该Service
任务配置访问权限,即指定哪些任务可以向该Service
任务发送IPC
消息。LiteIPC
的核心思想就是在内核态为每个Service
任务维护一个IPC
消息队列,该消息队列通过LiteIPC
设备文件向上层用户态程序分别提供代表收取IPC
消息的读操作和代表发送IPC
消息的写操作。
设备文件的接口层(VFS
)实现为g_liteIpcFops
,跟踪这几个函数就能够整明白整个实现LiteIPC
过程
LiteIpcOpen | 创建消息内存池
解读
- 进来先获取当前进程
OsCurrProcessGet()
,即为每个进程创建唯一的IPC
消息控制体,ProcIpcInfo
在进程控制块中,负责管理IPC
消息 - 初始化消息内存池,此处只申请结构体本身占用内存,真正的内存池在
LiteIpcMmap
中完成
LiteIpcMmap | 映射
解读
- 这个函数一定要看明白,重要部分已加注释,主要干了两件事。
- 通过
LOS_VMalloc
向内核堆空间申请了一段物理内存,参数是线性区的大小,并做好了映射,因是内核堆空间,所以分配的虚拟地址就是个内核地址,并将这个地址赋给了pool.kvaddr
- 通过
DoIpcMmap
将参数pcb
(用户进程)的IPC
消息池的pool.uvaddr
也映射到LOS_VMalloc
分配的物理内存上, 详看DoIpcMmap
的实现,因为太重要此处代码不做删改。 - 至次
LiteIPC
的准备工作已经完成,接下来就是操作/控制阶段了
LiteIpcIoctl | 控制
解读
LiteIPC
中有两个主要概念,一个是ServiceManager
,另一个是Service
。整个系统只能有一个ServiceManager
,而Service
可以有多个。ServiceManager
有两个主要功能:一是负责Service
的注册和注销,二是负责管理Service
的访问权限(只有有权限的任务(Task
)可以向对应的Service
发送IPC
消息)。IPC_SET_CMS
为设置ServiceManager
命令,IPC_CMS_CMD
为对Service
的管理命令。IPC_SEND_RECV_MSG
为消息的处理过程,消息的封装结合上篇理解,接收和发送消息对应的是LiteIpcRead
和LiteIpcWrite
两个函数。LiteIpcWrite
写消息指的是从用户空间向内核空间写数据,在消息内容体中已经指明这个消息时写给哪个任务的,如此达到了进程间(其实也是任务间)通讯的目的。- 大概流程就是从
LiteIpc
内存池中分配内核空间装用户空间的数据,注意一定要从LiteIpcNodeAlloc
分配,原因代码中也已注明。 - 有数据了就将数据挂到目标任务的
IPC
双向链表上,如果任务在等待读取消息(OS_TASK_WAIT_LITEIPC
)则唤醒目标任务执行,并发起调度LOS_Schedule
。
- 大概流程就是从
LiteIpcRead
和LiteIpcWrite
是遥相呼应,读消息指将内核空间数据读到用户空间处理。- 调度到目标任务后,将切到
LiteIpcRead
执行,此时读函数正在经历一个do … while(1) 死循环等待消息到来。LiteIpcRead
的最后是内核地址和用户地址的转换,这也是LiteIpc
最精彩的部分,它们指向同一块数据。 - 当
LiteIpcRead
读取不到消息时,即当前任务的消息链表为空时,任务会设置一个等待标签OS_TASK_WAIT_LITEIPC
,并将自己挂起,由OsSchedTaskWait
让出CPU
给其他任务继续执行,请反复理解读写函数。
- 调度到目标任务后,将切到
百文说内核 | 抓住主脉络
- 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
- 与代码需不断
debug
一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx
代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。 - 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,公众号回复 百文 可方便阅读。
按功能模块:
- 前因后果 >> 总目录 | 调度故事 | 内存主奴 | 源码注释 | 源码结构 | 静态站点 | 参考文档 |
- 基础工具 >> 双向链表 | 位图管理 | 用栈方式 | 定时器 | 原子操作 | 时间管理 |
- 加载运行 >> ELF格式 | ELF解析 | 静态链接 | 重定位 | 进程映像 |
- 进程管理 >> 进程管理 | 进程概念 | Fork | 特殊进程 | 进程回收 | 信号生产 | 信号消费 | Shell编辑 | Shell解析 |
- 编译构建 >> 编译环境 | 编译过程 | 环境脚本 | 构建工具 | gn应用 | 忍者ninja |
- 进程通讯 >> 自旋锁 | 互斥锁 | 进程通讯 | 信号量 | 事件控制 | 消息队列 | 共享内存 | 消息封装 | 消息映射 |
- 内存管理 >> 内存分配 | 内存管理 | 内存汇编 | 内存映射 | 内存规则 | 物理内存 |
- 任务管理 >> 时钟任务 | 任务调度 | 任务管理 | 调度队列 | 调度机制 | 线程概念 | 并发并行 | CPU | 系统调用 | 任务切换 |
- 文件系统 >> 文件概念 | 文件系统 | 索引节点 | 挂载目录 | 根文件系统 | VFS | 文件句柄 | 管道文件 |
- 硬件架构 >> 汇编基础 | 汇编传参 | 工作模式 | 寄存器 | 异常接管 | 汇编汇总 | 中断切换 | 中断概念 | 中断管理 |
- 设备驱动 >> 字符设备 | 控制台 | 远程登录 |
百万注源码 | 处处扣细节
-
百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。
-
< gitee | github | coding | codechina > 四大码仓推送 | 同步官方源码,公众号中回复 百万 可方便阅读。
