开源鸿蒙内核源码分析系列 | 通讯总览 | 内核跟人一样都喜欢八卦(转载)

开源鸿蒙内核源码分析系列 | 通讯总览 | 内核跟人一样都喜欢八卦(转载)

通信方式

数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到KB字节之间。(liteipc消息队列默认1K)

共享数据: 多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。

通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

The tower of Babel by Pieter Bruegel

进程间有九种通讯方式,下面我们就一一阐述:

1. 管道pipe(fs_syscall.c)

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。

管道的特质

  1. 其本质是一个伪文件(实为内核缓冲区)
  2. 由两个文件描述符引用,一个表示读端,一个表示写端。
  3. 规定数据从管道的写端流入管道,从读端流出。

管道的原理

管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。 

管道的局限性: 

  1. 数据自己读不能自己写。 
  2. 数据一旦被读走,便不在管道中存在,不可反复读取。 
  3. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。 
  4. 只能在有公共祖先的进程间使用管道。常见的通信方式有,单工通信、半双工通信、全双工通信。

这部分后系列篇文件相关篇中会重点讲,敬请关注。详细看 SysPipe 函数。

2. 信号(los_signal.c)

信号思想来自Unix,在发展了50年之后,许多方面都没有发生太大的变化。信号可以由内核产生,也可以由用户进程产生,并由内核传送给特定的进程或线程(组),若这个进程注册/安装了自己的信号处理程序,则内核会调用这个函数去处理信号,否则则执行默认的函数或者忽略。信号分为两大类:可靠信号与不可靠信号,前32种信号为不可靠信号,后32种为可靠信号。长这样:


#define SIGHUP    1  //终端挂起或者控制进程终止
#define SIGINT    2  //键盘中断(如break键被按下)
#define SIGQUIT   3  //键盘的退出键被按下
#define SIGILL    4  //非法指令
#define SIGTRAP   5  //跟踪陷阱(trace trap),启动进程,跟踪代码的执行
#define SIGABRT   6  //由abort(3)发出的退出指令
#define SIGIOT    SIGABRT 
#define SIGBUS    7  //总线错误 
#define SIGFPE    8  //浮点异常
#define SIGKILL   9    //常用的命令 kill 9 13 
#define SIGUSR1   10  //用户自定义信号1

信号为系统提供了一种进程间异步通讯的方式,一个进程不必通过任何操作来等待信号的到达。事实上,进程也不可能知道信号到底什么时候到达。一般来说,只需用户进程提供信号处理函数,内核会想方设法调用信号处理函数,处理过程如图所示:

个人把这种异步通讯过程理解为生产者(安装和发送信号)和消费者(捕捉和处理信号)两个部分。后篇会有讲解。

3. 消息队列(los_queue.c)

基本概念

队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的 不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。

任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时, 挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时, 挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将 读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。

消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。

队列特性

消息以先进先出的方式排队,支持异步读写。读队列和写队列都支持超时机制。每读取一条消息,就会将该消息节点设置为空闲。发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。一个任务能够从任意一个消息队列接收和发送消息。多个任务能够从同一个消息队列接收和发送消息。创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。

4.共享内存(shm.c)

共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块物理内存,每个进程都要单独对这块物理内存进行映射。当一个进程改变了这块地址中的内容的时候,该物理页框将被标记为脏页,如此其它进程都会知道内容发生了更改。

这部分后系列篇内存相关篇中会重点讲。

5.信号量(los_sem.c)

基本概念

信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数。

对信号量有个形象的比喻 停车场的停车位, 进停车场前看下屏幕上实时显示剩余车位,0表示不能进,只有大于0才能进入,进入后自动减1,出口处也加了监测,出去后剩余车位增加1个。

使用场景

在多任务系统中,信号量是一种非常灵活的同步方式,可以运用在多种场合中,实现锁、同步、资源计数等功能, 也能方便的用于任务与任务,中断与任务的同步中。常用于协助一组相互竞争的任务访问共享资源。

7.快锁 (los_futex.c)

futex 是Fast Userspace muTexes的缩写(快速用户空间互斥体),是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。

注解版同步到官方最新源码后,发现快锁的部分改动很大,这部分要重新注解,敬请留意。

8.事件 (los_event.c)

基本概念

事件(Event)是一种任务间通信的机制,可用于任务间的同步。

多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。多对多同步模型:多个任务等待多个事件的触发。

事件特点

任务通过创建事件控制块来触发事件或等待事件。事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。事件仅用于任务间的同步,不提供数据传输功能。多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。多个任务可以对同一事件进行读写操作。支持事件读写超时机制。

事件可应用于多种任务同步场景,在某些同步场景下可替代信号量。

使用场景

队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。

9. 文件消息队列 (hm_liteipc.c)

基于文件实现的消息队列,特点是队列中消息数量多(256个),传递消息内容大(可到1K)


#define SIGHUP    1  //终端挂起或者控制进程终止
#define SIGINT    2  //键盘中断(如break键被按下)
#define SIGQUIT   3  //键盘的退出键被按下
#define SIGILL    4  //非法指令
#define SIGTRAP   5  //跟踪陷阱(trace trap),启动进程,跟踪代码的执行
#define SIGABRT   6  //由abort(3)发出的退出指令
#define SIGIOT    SIGABRT 
#define SIGBUS    7  //总线错误 
#define SIGFPE    8  //浮点异常
#define SIGKILL   9    //常用的命令 kill 9 13 
#define SIGUSR1   10  //用户自定义信号1

文件消息队列隐约感觉鸿蒙的分布式通讯,跨屏之类的功能是靠它实现的,分布式的代码还没研究,尚不清楚,如果有了解的请告知。后续要重点研究下跨应用通讯的技术实现。

百文说内核 | 抓住主脉络

子曰:“诗三百,一言以蔽之,曰‘思无邪’。”——《论语》:为政篇。

百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在开源鸿蒙内核源码加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。
百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。

与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。百篇博客系列思维导图结构如下:

根据上图的思维导图,我们未来将要和大家一一分享以上大部分关键技术点的博客文章。

百万汉字注解.精读内核源码

如果大家觉得看文章不过瘾,想直接撸代码的话,可以去下面四大码仓围观同步注释内核源码:

gitee仓

https://gitee.com/weharmony/kernel_liteos_a_note

github仓 :

https://github.com/kuangyufei/kernel_liteos_a_note

codechina仓

https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note

coding仓

https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files

写在最后

我们最近正带着大家玩嗨OpenHarmony。如果你有用OpenHarmony开发的好玩的东东,或者有对OpenHarmony的深度技术剖析,想通过我们平台让更多的小伙伴知道和分享的,欢迎投稿,让我们一起嗨起来!有点子,有想法,有Demo,立刻联系我们:

合作邮箱:zzliang@atomsource.org