首页 文章 精选 留言 我的

精选列表

搜索[HarmonyOS],共1235篇文章
优秀的个人博客,低调大师

鸿蒙内核源码分析(源码注释篇) | 鸿蒙必须成功,也必然成功 | 百篇博客分析HarmonyOS源码

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | coding [>]() 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< osc | 51cto | harmony [>]() 百万汉字注解 kernel_liteos_a_note 是在鸿蒙官方开源项目 kernel_liteos_a 基础上给源码加上中文注解的版本. 同步官方源码历史 每月同步一次 2021/4/21 -- 官方优化了很多之前吐槽的地方,点赞鸿蒙的效率 2020/9/16 -- 中文注解版起点 为何要精读内核源码? 每位码农的学职生涯,都应精读一遍内核源码.以浇筑好计算机知识大厦的地基,地基纵深的坚固程度,很大程度能决定未来大厦能盖多高。那为何一定要精读细品呢? 因为内核代码本身并不太多,都是浓缩的精华,精读是让各个知识点高频出现,不孤立成点状记忆,让各点相连成线,线面成体,刻意练习,闪爆大脑,如此短时间内容易结成一张高浓度,高密度的底层网,内核画面越描越清晰,越雕越深刻,不断训练大脑肌肉记忆,将记忆从临时区转移到永久区。跟骑单车一样,一旦学会,即便多年不骑,照样跨上就走,游刃有余。 热爱是所有的理由和答案 因大学时阅读 linux 2.6 内核痛并快乐的经历,一直有个心愿,如何让更多对内核感兴趣的朋友减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃.但因过程种种,多年一直没有行动,基本要放弃这件事了.恰逢 2020/9/10 鸿蒙正式开源,重新激活了多年的心愿,就有那么点一发不可收拾了. 到 2021/3/10 刚好半年, 对内核源码的注解已完成了 70% ,对内核源码的博客分析已完成了40篇, 每天都很充实,很兴奋,连做梦内核代码都在往脑海里鱼贯而入.如此疯狂地做一件事还是当年谈恋爱的时候, 只因热爱, 热爱是所有的理由和答案. :P (〃・ิ‿・ิ)ゞ鸿蒙内核开发者 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此.精读内核源码加注并整理成档是件很有挑战的事,时间上要以月甚至年为单位,但正因为很难才值得去做! 干困难事,方有所得;专注聚焦,必有所获. 从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的.可以毫不夸张的说鸿蒙内核源码可作为大学 C语言,数据结构,操作系统,汇编语言,计算机组成原理 五门课程的教学项目.如此宝库,不深入研究实在是暴殄天物,于心不忍,注者坚信鸿蒙大势所趋,未来可期,其必须成功,也必然成功,誓做其坚定的追随者和传播者. 加注方式是怎样的? 因鸿蒙内核6W+代码量,本身只有较少的注释, 中文注解以不对原有代码侵入为前提,源码中所有英文部分都是原有注释,所有中文部分都是中文版的注释,同时为方便同步官方版本的更新,尽量不去增加代码的行数,不破坏文件的结构,注释多类似以下的方式: 在重要模块的.c/.h文件开始位置先对模块功能做整体的介绍,例如异常接管模块注解如图所示: 注解过程中查阅了很多的资料和书籍,在具体代码处都附上了参考链接. 而函数级注解会详细到重点行,甚至每一行, 例如申请互斥锁的主体函数,不可谓不重要,而官方注释仅有一行,如图所示 另外画了一些字符图方便理解,直接嵌入到头文件中,比如虚拟内存的全景图,因没有这些图是很难理解虚拟内存是如何管理的. 理解内核的三个层级 注者认为理解内核可分三个层级: 普通概念映射级: 这一级不涉及专业知识,用大众所熟知的公共认知就能听明白是个什么概念,也就是说用一个普通人都懂的概念去诠释或者映射一个他们从没听过的概念.让陌生的知识点与大脑中烂熟于心的知识点建立多重链接,加深记忆.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? 不一定!在系列篇中试图用 鸿蒙内核源码分析(总目录)之故事篇 去引导这一层级的认知,希望能卷入更多的人来关注基础软件,尤其是那些资本大鳄,加大对基础软件的投入. 专业概念抽象级: 对抽象的专业逻辑概念具体化认知, 比如虚拟内存,老百姓是听不懂的,学过计算机的人都懂,具体怎么实现的很多人又都不懂了,但这并不妨碍成为一个优秀的上层应用开发者,因为虚拟内存已经被抽象出来,目的是要屏蔽上层对它具体实现的认知.试图用 鸿蒙内核源码分析(总目录)百篇博客 去拆解那些已经被抽象出来的专业概念, 希望能卷入更多对内核感兴趣的应用软件人才流入基础软件生态, 应用软件咱们是无敌宇宙,但基础软件却很薄弱. 具体微观代码级: 这一级是具体到每一行代码的实现,到了用代码指令级的地步,这段代码是什么意思?为什么要这么设计?有没有更好的方案? 鸿蒙内核源码注解分析 试图从细微处去解释代码实现层,英文真的是天生适合设计成编程语言的人类语言,计算机的01码映射到人类世界的26个字母,诞生了太多的伟大奇迹.但我们的母语注定了很大部分人存在着自然语言层级的理解映射,希望鸿蒙内核源码注解分析能让更多爱好者快速的理解内核,共同进步. 百篇博客分析 鸿蒙源码百篇博客 往期回顾 在给 鸿蒙内核源码加中文注释 过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感.百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 写文章比写代码累多了,越深入研究,越觉得没写好,所以文章和注解会反复修正, .xx代表修改的次数, 将持续完善源码注解和文档内容,精雕细琢,言简意赅, 尽全力打磨精品内容. v51.xx (ELF反汇编篇) | 程序的入口函数并不是main [<]() harmony | 51cto | osc [>]() v50.xx (编译环境篇) | 编译鸿蒙看这篇或许真的够了 [<]() harmony | 51cto | osc [>]() v49.xx (信号消费篇) | 谁让CPU连续四次换栈运行 [<]() harmony | 51cto | osc [>]() v48.xx (信号生产篇) | 信号已经五十多岁了 [<]() harmony | 51cto | osc [>]() v47.xx (进程回收篇) | 进程在临终前如何向老祖宗托孤 [<]() harmony | 51cto | osc [>]() v46.xx (特殊进程篇) | 龙生龙,凤生凤,老鼠生儿会打洞 [<]() harmony | 51cto | osc [>]() v45.xx (fork篇) | fork是如何做到调用一次,返回两次的 [<]() harmony | 51cto | osc [>]() v44.xx (中断管理篇) | 硬中断的实现像观察者模式 [<]() harmony | 51cto | osc [>]() v43.xx (中断概念篇) | 外人眼中权势滔天的当红海公公 [<]() harmony | 51cto | osc [>]() v42.xx (中断切换篇) | 中断切换又在切换什么 [<]() harmony | 51cto | osc [>]() v41.xx (任务切换篇) | 汇编告诉任务到底在切换什么 [<]() harmony | 51cto | osc [>]() v40.xx (汇编汇总篇) | 所有的汇编代码都在呢 [<]() harmony | 51cto | osc [>]() v39.xx (异常接管篇) | 社会很单纯,复杂的是人 [<]() harmony | 51cto | osc [>]() v38.xx (寄存器篇) | 看完再也不对寄存器怕怕 [<]() harmony | 51cto | osc [>]() v37.xx (系统调用篇) | 系统调用到底经历了什么 [<]() harmony | 51cto | osc [>]() v36.xx (工作模式篇) | cpu是韦小宝,有哪七个老婆 [<]() harmony | 51cto | osc [>]() v35.xx (时间管理篇) | tick是操作系统的基本时间单位 [<]() harmony | 51cto | osc [>]() v34.xx (原子操作篇) | 是谁在为原子操作保驾护航 [<]() harmony | 51cto | osc [>]() v33.xx (消息队列篇) | 进程间如何异步解耦传递大数据 [<]() harmony | 51cto | osc [>]() v32.xx (cpu篇) | 整个内核就是一个死循环 [<]() harmony | 51cto | osc [>]() v31.xx (定时器篇) | 内核最高优先级任务是谁 [<]() harmony | 51cto | osc [>]() v30.xx (事件控制篇) | 任务间多对多的同步方案 [<]() harmony | 51cto | osc [>]() v29.xx (信号量篇) | 信号量解决任务的什么问题 [<]() harmony | 51cto | osc [>]() v28.xx (进程通讯篇) | 九种进程间通讯方式速揽 [<]() harmony | 51cto | osc [>]() v27.xx (互斥锁篇) | 比自旋锁丰满的互斥锁 [<]() harmony | 51cto | osc [>]() v26.xx (自旋锁篇) | 自旋锁当立贞节牌坊 [<]() harmony | 51cto | osc [>]() v25.xx (并发并行篇) | 两个字永远记住二者区别 [<]() harmony | 51cto | osc [>]() v24.xx (进程概念篇) | 进程在管理哪些资源 [<]() harmony | 51cto | osc [>]() v23.xx (汇编传参篇) | 汇编如何传递复杂的参数 [<]() harmony | 51cto | osc [>]() v22.xx (汇编基础篇) | cpu在哪里打卡上班 [<]() harmony | 51cto | osc [>]() v21.xx (线程概念篇) | 是谁在不断的折腾cpu [<]() harmony | 51cto | osc [>]() v20.xx (用栈方式篇) | 栈是构建底层运行的基础 [<]() harmony | 51cto | osc [>]() v19.xx (位图管理篇) | 为何进程和线程优先级都是32个 [<]() harmony | 51cto | osc [>]() v18.xx (源码结构篇) | 梳理内核源文件的作用和含义 [<]() harmony | 51cto | osc [>]() v17.xx (物理内存篇) | 怎么管理物理内存 [<]() harmony | 51cto | osc [>]() v16.xx (内存规则篇) | 内存管理到底在管什么 [<]() harmony | 51cto | osc [>]() v15.xx (内存映射篇) | 虚拟内存虚在哪里 [<]() harmony | 51cto | osc [>]() v14.xx (内存汇编篇) | 什么是虚拟内存的实现基础 [<]() harmony | 51cto | osc [>]() v13.xx (源码注释篇) | 鸿蒙必须成功,也必然成功 [<]() harmony | 51cto | osc [>]() v12.xx (内存管理篇) | 虚拟内存全景图是怎样的 [<]() harmony | 51cto | osc [>]() v11.xx (内存分配篇) | 内存有哪些分配方式 [<]() harmony | 51cto | osc [>]() v10.xx (内存主奴篇) | 紫禁城的主子和奴才如何相处 [<]() harmony | 51cto | osc [>]() v09.xx (调度故事篇) | 用故事说内核调度过程 [<]() harmony | 51cto | osc [>]() v08.xx (总目录) | 百万汉字注解 百篇博客分析 [<]() harmony | 51cto | osc [>]() v07.xx (调度机制篇) | 任务是如何被调度执行的 [<]() harmony | 51cto | osc [>]() v06.xx (调度队列篇) | 内核有多少个调度队列 [<]() harmony | 51cto | osc [>]() v05.xx (任务管理篇) | 任务池是如何管理的 [<]() harmony | 51cto | osc [>]() v04.xx (任务调度篇) | 任务是内核调度的单元 [<]() harmony | 51cto | osc [>]() v03.xx (时钟任务篇) | 谁是触发调度的最大动力 [<]() harmony | 51cto | osc [>]() v02.xx (进程管理篇) | 进程是内核资源管理单元 [<]() harmony | 51cto | osc [>]() v01.xx (双向链表篇) | 谁是内核最重要结构体 [<]() harmony | 51cto | osc [>]() 主流站点输出 进入 >> osc | csdn | 51cto | 掘金 | 公众号 | 头条号 | gitee | github Fork Me 注解几乎占用了所有的空闲时间,每天都会更新,每天都有新感悟,一行行源码在不断的刷新和拓展对内核知识的认知边界. 对已经关注和fork的同学请及时同步最新的注解内容. 内核知识点体量实在太过巨大,跟软件一样,会存在bug,但会反复Debug. 有哪些特殊的记号 搜索 @note_pic 可查看绘制的全部字符图 搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善 搜索 @note_thinking 是一些的思考和建议 搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。 搜索 @note_good 是给源码点赞的地方 新增zzzz目录 中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那帮朋友,你的微信里应该也有他们熟悉的身影吧 :|P 两句话 热爱是所有的理由和答案 - turing 不经过深度思考的人生不值得一过 - turing

优秀的个人博客,低调大师

鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析HarmonyOS源码

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新[<]() gitee | github | csdn | coding [>]() 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中[<]() osc | 51cto | csdn | harmony [>]() 下载.鸿蒙内核源码分析(百篇博客.定期更新).pdf 百万汉字注解 kernel_liteos_a_note 是在鸿蒙官方开源项目 kernel_liteos_a 基础上给源码加上中文注解的版本. 同步官方源码历史 每月同步一次 2021/4/21 -- 官方优化了很多之前吐槽的地方,点赞鸿蒙的效率 2020/9/16 -- 中文注解版起点 为何要精读内核源码? 每位码农的学职生涯,都应精读一遍内核源码.以浇筑好计算机知识大厦的地基,地基纵深的坚固程度,很大程度能决定未来大厦能盖多高。那为何一定要精读细品呢? 因为内核代码本身并不太多,都是浓缩的精华,精读是让各个知识点高频出现,不孤立成点状记忆,让各点相连成线,线面成体,刻意练习,闪爆大脑,如此短时间内容易结成一张高浓度,高密度的底层网,内核画面越描越清晰,越雕越深刻,不断训练大脑肌肉记忆,将记忆从临时区转移到永久区。跟骑单车一样,一旦学会,即便多年不骑,照样跨上就走,游刃有余。 热爱是所有的理由和答案 因大学时阅读 linux 2.6 内核痛并快乐的经历,一直有个心愿,如何让更多对内核感兴趣的朋友减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃.但因过程种种,多年一直没有行动,基本要放弃这件事了.恰逢 2020/9/10 鸿蒙正式开源,重新激活了多年的心愿,就有那么点一发不可收拾了. 到 2021/3/10 刚好半年, 对内核源码的注解已完成了 70% ,对内核源码的博客分析已完成了40篇, 每天都很充实,很兴奋,连做梦内核代码都在往脑海里鱼贯而入.如此疯狂地做一件事还是当年谈恋爱的时候, 只因热爱, 热爱是所有的理由和答案. :P (〃・ิ‿・ิ)ゞ鸿蒙内核开发者 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此.精读内核源码加注并整理成档是件很有挑战的事,时间上要以月甚至年为单位,但正因为很难才值得去做! 干困难事,方有所得;专注聚焦,必有所获. 从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的.可以毫不夸张的说鸿蒙内核源码可作为大学 C语言,数据结构,操作系统,汇编语言,计算机组成原理 五门课程的教学项目.如此宝库,不深入研究实在是暴殄天物,于心不忍,注者坚信鸿蒙大势所趋,未来可期,其必定成功,也必然成功,誓做其坚定的追随者和传播者. 加注方式是怎样的? 因鸿蒙内核6W+代码量,本身只有较少的注释, 中文注解以不对原有代码侵入为前提,源码中所有英文部分都是原有注释,所有中文部分都是中文版的注释,同时为方便同步官方版本的更新,尽量不去增加代码的行数,不破坏文件的结构,注释多类似以下的方式: 在重要模块的.c/.h文件开始位置先对模块功能做整体的介绍,例如异常接管模块注解如图所示: 注解过程中查阅了很多的资料和书籍,在具体代码处都附上了参考链接. 而函数级注解会详细到重点行,甚至每一行, 例如申请互斥锁的主体函数,不可谓不重要,而官方注释仅有一行,如图所示 另外画了一些字符图方便理解,直接嵌入到头文件中,比如虚拟内存的全景图,因没有这些图是很难理解虚拟内存是如何管理的. 理解内核的三个层级 注者认为理解内核可分三个层级: 普通概念映射级: 这一级不涉及专业知识,用大众所熟知的公共认知就能听明白是个什么概念,也就是说用一个普通人都懂的概念去诠释或者映射一个他们从没听过的概念.让陌生的知识点与大脑中烂熟于心的知识点建立多重链接,加深记忆.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? 不一定!在系列篇中试图用 鸿蒙内核源码分析(总目录)之故事篇 去引导这一层级的认知,希望能卷入更多的人来关注基础软件,尤其是那些资本大鳄,加大对基础软件的投入. 专业概念抽象级: 对抽象的专业逻辑概念具体化认知, 比如虚拟内存,老百姓是听不懂的,学过计算机的人都懂,具体怎么实现的很多人又都不懂了,但这并不妨碍成为一个优秀的上层应用开发者,因为虚拟内存已经被抽象出来,目的是要屏蔽上层对它具体实现的认知.试图用 鸿蒙内核源码分析(总目录)百篇博客 去拆解那些已经被抽象出来的专业概念, 希望能卷入更多对内核感兴趣的应用软件人才流入基础软件生态, 应用软件咱们是无敌宇宙,但基础软件却很薄弱. 具体微观代码级: 这一级是具体到每一行代码的实现,到了用代码指令级的地步,这段代码是什么意思?为什么要这么设计?有没有更好的方案? 鸿蒙内核源码注解分析 试图从细微处去解释代码实现层,英文真的是天生适合设计成编程语言的人类语言,计算机的01码映射到人类世界的26个字母,诞生了太多的伟大奇迹.但我们的母语注定了很大部分人存在着自然语言层级的理解映射,希望鸿蒙内核源码注解分析能让更多爱好者快速的理解内核,共同进步. 百篇博客分析 鸿蒙源码百篇博客 往期回顾 在给 鸿蒙内核源码加中文注释 过程中,整理出以下文章.内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感.百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思.更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了.:P 写文章比写代码累多了,越深入研究,越觉得没写好,所以文章和注解会反复修正, .xx代表修改的次数, 将持续完善源码注解和文档内容,精雕细琢,言简意赅, 尽全力打磨精品内容. v51.xx (ELF反汇编篇) | 程序的入口函数并不是main [<]() harmony | 51cto | osc [>]() v50.xx (编译环境篇) | 编译鸿蒙看这篇或许真的够了 [<]() harmony | 51cto | osc [>]() v49.xx (信号消费篇) | 谁让CPU连续四次换栈运行 [<]() harmony | 51cto | osc [>]() v48.xx (信号生产篇) | 信号已经五十多岁了 [<]() harmony | 51cto | osc [>]() v47.xx (进程回收篇) | 进程在临终前如何向老祖宗托孤 [<]() harmony | 51cto | osc [>]() v46.xx (特殊进程篇) | 龙生龙,凤生凤,老鼠生儿会打洞 [<]() harmony | 51cto | osc [>]() v45.xx (fork篇) | fork是如何做到调用一次,返回两次的 [<]() harmony | 51cto | osc [>]() v44.xx (中断管理篇) | 硬中断的实现像观察者模式 [<]() harmony | 51cto | osc [>]() v43.xx (中断概念篇) | 外人眼中权势滔天的当红海公公 [<]() harmony | 51cto | osc [>]() v42.xx (中断切换篇) | 中断切换又在切换什么 [<]() harmony | 51cto | osc [>]() v41.xx (任务切换篇) | 汇编告诉任务到底在切换什么 [<]() harmony | 51cto | osc [>]() v40.xx (汇编汇总篇) | 所有的汇编代码都在呢 [<]() harmony | 51cto | osc [>]() v39.xx (异常接管篇) | 社会很单纯,复杂的是人 [<]() harmony | 51cto | osc [>]() v38.xx (寄存器篇) | 看完再也不对寄存器怕怕 [<]() harmony | 51cto | osc [>]() v37.xx (系统调用篇) | 系统调用到底经历了什么 [<]() harmony | 51cto | osc [>]() v36.xx (工作模式篇) | cpu是韦小宝,有哪七个老婆 [<]() harmony | 51cto | osc [>]() v35.xx (时间管理篇) | tick是操作系统的基本时间单位 [<]() harmony | 51cto | osc [>]() v34.xx (原子操作篇) | 是谁在为原子操作保驾护航 [<]() harmony | 51cto | osc [>]() v33.xx (消息队列篇) | 进程间如何异步解耦传递大数据 [<]() harmony | 51cto | osc [>]() v32.xx (cpu篇) | 整个内核就是一个死循环 [<]() harmony | 51cto | osc [>]() v31.xx (定时器篇) | 内核最高优先级任务是谁 [<]() harmony | 51cto | osc [>]() v30.xx (事件控制篇) | 任务间多对多的同步方案 [<]() harmony | 51cto | osc [>]() v29.xx (信号量篇) | 信号量解决任务的什么问题 [<]() harmony | 51cto | osc [>]() v28.xx (进程通讯篇) | 九种进程间通讯方式速揽 [<]() harmony | 51cto | osc [>]() v27.xx (互斥锁篇) | 比自旋锁丰满的互斥锁 [<]() harmony | 51cto | osc [>]() v26.xx (自旋锁篇) | 自旋锁当立贞节牌坊 [<]() harmony | 51cto | osc [>]() v25.xx (并发并行篇) | 两个字永远记住二者区别 [<]() harmony | 51cto | osc [>]() v24.xx (进程概念篇) | 进程在管理哪些资源 [<]() harmony | 51cto | osc [>]() v23.xx (汇编传参篇) | 汇编如何传递复杂的参数 [<]() harmony | 51cto | osc [>]() v22.xx (汇编基础篇) | cpu在哪里打卡上班 [<]() harmony | 51cto | osc [>]() v21.xx (线程概念篇) | 是谁在不断的折腾cpu [<]() harmony | 51cto | osc [>]() v20.xx (用栈方式篇) | 栈是构建底层运行的基础 [<]() harmony | 51cto | osc [>]() v19.xx (位图管理篇) | 为何进程和线程优先级都是32个 [<]() harmony | 51cto | osc [>]() v18.xx (源码结构篇) | 梳理内核源文件的作用和含义 [<]() harmony | 51cto | osc [>]() v17.xx (物理内存篇) | 怎么管理物理内存 [<]() harmony | 51cto | osc [>]() v16.xx (内存规则篇) | 内存管理到底在管什么 [<]() harmony | 51cto | osc [>]() v15.xx (内存映射篇) | 虚拟内存虚在哪里 [<]() harmony | 51cto | osc [>]() v14.xx (内存汇编篇) | 什么是虚拟内存的实现基础 [<]() harmony | 51cto | osc [>]() v13.xx (源码注释篇) | 鸿蒙必须成功,也必然成功 [<]() harmony | 51cto | osc [>]() v12.xx (内存管理篇) | 虚拟内存全景图是怎样的 [<]() harmony | 51cto | osc [>]() v11.xx (内存分配篇) | 内存有哪些分配方式 [<]() harmony | 51cto | osc [>]() v10.xx (内存主奴篇) | 紫禁城的主子和奴才如何相处 [<]() harmony | 51cto | osc [>]() v09.xx (调度故事篇) | 用故事说内核调度过程 [<]() harmony | 51cto | osc [>]() v08.xx (总目录) | 百万汉字注解 百篇博客分析 [<]() harmony | 51cto | osc [>]() v07.xx (调度机制篇) | 任务是如何被调度执行的 [<]() harmony | 51cto | osc [>]() v06.xx (调度队列篇) | 内核有多少个调度队列 [<]() harmony | 51cto | osc [>]() v05.xx (任务管理篇) | 任务池是如何管理的 [<]() harmony | 51cto | osc [>]() v04.xx (任务调度篇) | 任务是内核调度的单元 [<]() harmony | 51cto | osc [>]() v03.xx (时钟任务篇) | 谁是触发调度的最大动力 [<]() harmony | 51cto | osc [>]() v02.xx (进程管理篇) | 进程是内核资源管理单元 [<]() harmony | 51cto | osc [>]() v01.xx (双向链表篇) | 谁是内核最重要结构体 [<]() harmony | 51cto | osc [>]() 进入 >> osc | csdn | 51cto | 掘金 | 公众号 | 头条号 | gitee | github Fork Me 注解几乎占用了所有的空闲时间,每天都会更新,每天都有新感悟,一行行源码在不断的刷新和拓展对内核知识的认知边界. 对已经关注和fork的同学请及时同步最新的注解内容. 内核知识点体量实在太过巨大,跟软件一样,会存在bug,但会反复Debug. 有哪些特殊的记号 搜索 @note_pic 可查看绘制的全部字符图 搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善 搜索 @note_thinking 是一些的思考和建议 搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。 搜索 @note_good 是给源码点赞的地方 新增zzzz目录 中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那帮朋友,你的微信里应该也有他们熟悉的身影吧 :|P 百篇博客.定期更新 下载.鸿蒙内核源码分析(百篇博客.定期更新).pdf 热爱是所有的理由和答案 - turing 百万汉字注解鸿蒙源码,百篇博客深挖地基工程. 原创不易,欢迎转载,但麻烦请注明出处.

优秀的个人博客,低调大师

| 中文注解HarmonyOS源码 | v25.01

鸿蒙内核源码中文注解 >> 精读内核源码,中文注解分析,深挖地基工程,大脑永久记忆,四大源码仓每日同步更新 本篇说清楚并发并行 读本篇之前建议先读 鸿蒙内核源码分析(总目录) 进程+线程篇,会对并行并发更深的理解. 理解并发概念 并发(Concurrent):多个线程在单个核心运行,同一时间只能一个线程运行,内核不停切换线程,看起来像同时运行,实际上是线程被高速的切换. 通俗好理解的比喻就是高速单行道,单行道指的是CPU的核数,跑的车就是线程(任务),进程就是管理车的公司,一个公司可以有很多台车.并发和并行跟CPU的核数有关.车道上同时只能跑一辆车,但因为指挥系统很牛,够快,在毫秒级内就能换车跑,人根本感知不到切换.所以外部的感知会是同时在进行,实现了微观上的串行,宏观上的并行. 线程切换的本质是CPU要换场地上班,去哪里上班由哪里提供场地,那个场地就是任务栈,每个任务栈中保存了上班的各种材料,来了就行立马干活.那些材料就是任务上下文.简单的说就是上次活干到那里了,回来继续接着干.上下文由任务栈自己保存,CPU不管的,它来了只负责任务交过来的材料,材料显示去哪里搬砖它就去哪里搬砖. 记住一个单词就能记住并行并发的区别, 发单,发单(并发单行). 理解并行概念 并行(Parallel)每个线程分配给独立的CPU核运行,多线程真正的同时运行. 通俗好理解的比喻就是高速多行道,实现了微观和宏观上同时进行. 并行当然是快,人多了干活就不那么累,但干活人多了必然会带来人多的管理问题,会把问题变复杂,请想想会出现哪些问题? 理解协程概念 这里说下协程,例如go语言是有协程支持的,其实协程跟内核层没有关系,是应用层的概念.是在线程之上更高层的封装,用通俗的比喻来说就是在车内另外搞了几条车道玩.其对内核来说没有新东西,内核只负责车的调度,至于车内你想怎么弄那是应用程序自己的事.本质的区别是CPU根本没有换地方上班(没有被调度),而并发/并行都是换地方上班了. 内核如何描述CPU typedef struct { SortLinkAttribute taskSortLink; /* task sort link */ //每个CPU core 都有一个task排序链表 SortLinkAttribute swtmrSortLink; /* swtmr sort link */ //每个CPU core 都有一个定时器排序链表 UINT32 idleTaskID; /* idle task id */ //空闲任务ID 见于 OsIdleTaskCreate UINT32 taskLockCnt; /* task lock flag */ //任务锁的数量,当 > 0 的时候,需要重新调度了 UINT32 swtmrHandlerQueue; /* software timer timeout queue id */ //软时钟超时队列句柄 UINT32 swtmrTaskID; /* software timer task id */ //软时钟任务ID UINT32 schedFlag; /* pending scheduler flag */ //调度标识 INT_NO_RESCH INT_PEND_RESCH #if (LOSCFG_KERNEL_SMP == YES) UINT32 excFlag; /* cpu halt or exc flag */ //CPU处于停止或运行的标识 #endif } Percpu; Percpu g_percpu[LOSCFG_KERNEL_CORE_NUM];//全局CPU数组 这是内核对CPU的描述,主要是两个排序链表,一个是任务的排序,一个是定时器的排序.什么意思? 在系列篇中多次提过,任务是内核的调度单元,注意可不是进程,虽然调度也需要进程参与,也需要切换进程,切换用户空间.但调度的核心是切换任务,每个任务的代码指令才是CPU的粮食,它吃的是一条条的指令.每个任务都必须指定取粮地址(即入口函数). 另外还有一个东西能提供入口函数,就是定时任务.很重要也很常用,没它某宝每晚9点的准时秒杀实现不了.在内核每个CPU都有自己独立的任务和定时器链表. 每次Tick的到来,处理函数会去扫描这两个链表,看有没有定时器超时的任务需要执行,有则立即执行定时任务,定时任务是所有任务中优先级最高的,0号优先级,在系列篇中有专门讲定时器任务,可自行翻看. LOSCFG_KERNEL_SMP # if (LOSCFG_KERNEL_SMP == YES) # define LOSCFG_KERNEL_CORE_NUM LOSCFG_KERNEL_SMP_CORE_NUM //多核情况下支持的CPU核数 # else # define LOSCFG_KERNEL_CORE_NUM 1 //单核配置 # endif 多CPU核的操作系统有3种处理模式(SMP+AMP+BMP) 鸿蒙实现的是 SMP 的方式 非对称多处理(Asymmetric multiprocessing,AMP)每个CPU内核运行一个独立的操作系统或同一操作系统的独立实例(instantiation)。 对称多处理(Symmetric multiprocessing,SMP)一个操作系统的实例可以同时管理所有CPU内核,且应用并不绑定某一个内核。 混合多处理(Bound multiprocessing,BMP)一个操作系统的实例可以同时管理所有CPU内核,但每个应用被锁定于某个指定的核心。 宏LOSCFG_KERNEL_SMP表示对多CPU核的支持,鸿蒙默认是打开LOSCFG_KERNEL_SMP的。 多CPU核支持 鸿蒙内核对CPU的操作见于 los_mp.c ,因文件不大,这里把代码都贴出来了. #if (LOSCFG_KERNEL_SMP == YES) //给参数CPU发送调度信号 VOID LOS_MpSchedule(UINT32 target)//target每位对应CPU core { UINT32 cpuid = ArchCurrCpuid(); target &= ~(1U << cpuid);//获取除了自身之外的其他CPU HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE);//向目标CPU发送调度信号,核间中断(Inter-Processor Interrupts),IPI } //硬中断唤醒处理函数 VOID OsMpWakeHandler(VOID) { /* generic wakeup ipi, do nothing */ } //硬中断调度处理函数 VOID OsMpScheduleHandler(VOID) {//将调度标志设置为与唤醒功能不同,这样就可以在硬中断结束时触发调度程序。 /* * set schedule flag to differ from wake function, * so that the scheduler can be triggered at the end of irq. */ OsPercpuGet()->schedFlag = INT_PEND_RESCH;//给当前Cpu贴上调度标签 } //硬中断暂停处理函数 VOID OsMpHaltHandler(VOID) { (VOID)LOS_IntLock(); OsPercpuGet()->excFlag = CPU_HALT;//让当前Cpu停止工作 while (1) {}//陷入空循环,也就是空闲状态 } //MP定时器处理函数, 递归检查所有可用任务 VOID OsMpCollectTasks(VOID) { LosTaskCB *taskCB = NULL; UINT32 taskID = 0; UINT32 ret; /* recursive checking all the available task */ for (; taskID <= g_taskMaxNum; taskID++) { //递归检查所有可用任务 taskCB = &g_taskCBArray[taskID]; if (OsTaskIsUnused(taskCB) || OsTaskIsRunning(taskCB)) { continue; } /* 虽然任务状态不是原子的,但此检查可能成功,但无法完成删除,此删除将在下次运行之前处理 * though task status is not atomic, this check may success but not accomplish * the deletion; this deletion will be handled until the next run. */ if (taskCB->signal & SIGNAL_KILL) {//任务收到被干掉信号 ret = LOS_TaskDelete(taskID);//干掉任务,回归任务池 if (ret != LOS_OK) { PRINT_WARN("GC collect task failed err:0x%x\n", ret); } } } } //MP(multiprocessing) 多核处理器初始化 UINT32 OsMpInit(VOID) { UINT16 swtmrId; (VOID)LOS_SwtmrCreate(OS_MP_GC_PERIOD, LOS_SWTMR_MODE_PERIOD, //创建一个周期性,持续时间为 100个tick的定时器 (SWTMR_PROC_FUNC)OsMpCollectTasks, &swtmrId, 0);//OsMpCollectTasks为超时回调函数 (VOID)LOS_SwtmrStart(swtmrId);//开始定时任务 return LOS_OK; } #endif 代码一一都加上了注解,这里再一一说明下: 1.OsMpInit 多CPU核的初始化, 多核情况下每个CPU都有各自的编号, 内核有分成主次CPU, 0号默认为主CPU, OsMain()由主CPU执行,被汇编代码调用. 初始化只开了个定时任务,只干一件事就是回收不用的任务.回收的条件是任务是否收到了被干掉的信号. 例如shell命令 kill 9 14 ,意思是干掉14号线程的信号,这个信号会被线程保存起来. 可以选择自杀也可以等着被杀. 这里要注意,鸿蒙有两种情况下任务不能被干掉, 一种是系统任务不能被干掉的, 第二种是正在运行状态的任务. 2.次级CPU的初始化 同样由汇编代码调用,通过以下函数执行,完成每个CPU核的初始化 //次级CPU初始化,本函数执行的次数由次级CPU的个数决定. 例如:在四核情况下,会被执行3次, 0号通常被定义为主CPU 执行main LITE_OS_SEC_TEXT_INIT VOID secondary_cpu_start(VOID) { #if (LOSCFG_KERNEL_SMP == YES) UINT32 cpuid = ArchCurrCpuid(); OsArchMmuInitPerCPU();//每个CPU都需要初始化MMU OsCurrTaskSet(OsGetMainTask());//设置CPU的当前任务 /* increase cpu counter */ LOS_AtomicInc(&g_ncpu); //统计CPU的数量 /* store each core's hwid */ CPU_MAP_SET(cpuid, OsHwIDGet());//存储每个CPU的 hwid HalIrqInitPercpu(); //CPU硬件中断初始化 OsCurrProcessSet(OS_PCB_FROM_PID(OsGetKernelInitProcessID())); //设置内核进程为CPU进程 OsSwtmrInit(); //定时任务初始化,每个CPU维护自己的定时器队列 OsIdleTaskCreate(); //创建空闲任务,每个CPU维护自己的任务队列 OsStart(); //本CPU正式启动在内核层的工作 while (1) { __asm volatile("wfi");//wait for Interrupt 等待中断,即下一次中断发生前都在此hold住不干活 }//类似的还有 WFE: wait for Events 等待事件,即下一次事件发生前都在此hold住不干活 #endif } 可以看出次级CPU有哪些初始化步骤: 第一:初始化MMU,OsArchMmuInitPerCPU 第二:设置当前任务 OsCurrTaskSet 第三:初始化硬件中断 HalIrqInitPercpu 第四:初始化定时器队列 OsSwtmrInit 第五:创建空任务 OsIdleTaskCreate, 外面没有任务的时CPU就待在这个空任务里自己转圈圈. 第六:开始自己的工作流程 OsStart,正式开始工作,跑任务 多CPU核还有哪些问题? 1.CPU之间抢资源的情况要怎么处理? 2.CPU之间通讯(也叫核间通讯)怎么解决? 3.如果确保两个CPU不会同时执行同一个任务? 4.汇编代码如何实现对各CPU的调动 请前往系列篇或直接前往内核注解代码查看.这里不再做说明. 喜欢就请收藏吧 各大站点搜 "鸿蒙内核源码分析" ,快速找到组织. 鸿蒙内核源码分析系列篇 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新

优秀的个人博客,低调大师

| 中文注解HarmonyOS源码 | v22.01

鸿蒙内核源码注释中文版 < Gitee仓 | CSDN仓 | Github仓 | Coding仓 >精读内核源码,中文注解分析,深挖地基工程,构建底层网图,四大码仓每日同步更新 鸿蒙源码分析系列篇 < CSDN | OSCHINA | WeHarmony | 源动力 >故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新 本篇通过拆解一段很简单的汇编代码来快速认识汇编,为读懂鸿蒙汇编打基础.系列篇后续将逐个剖析鸿蒙的汇编文件. 第一: 要认定汇编语言一定是简单的,没有高深的东西,无非就是数据的搬来搬去,运行时数据主要待在两个地方:内存和寄存器。寄存器是CPU内部存储器,离运算器最近,所以最快. 第二: 运行空间(栈空间)就是CPU打卡上班的地方,内核设计者规定谁请CPU上班由谁提供场地,用户程序提供的场地叫用户栈,敏感工作CPU要带回公司做,公司提供的场地叫内核栈,敏感工作叫系统调用,系统调用的本质理解是CPU要切换工作模式即切换办公场地。 第三:CPU的工作顺序是流水线的,它只认指令,而且只去一个地方(指向代码段的PC寄存器)拿指令运算消化。指令集是告诉外界我CPU能干什么活并提供对话指令,汇编语言是人和CPU能愉快沟通不拧巴的共识语言。一一对应了CPU指令,又能确保记性不好的人类能模块化的设计idea, 先看一段C编译成汇编代码再来说模块化。 //编译器: armv7-a clang (trunk) //++++++++++++ square(c -> 汇编)++++++++++++++++++++++++ int square(int a,int b){ return a*b; } square(int, int): sub sp, sp, #8 @sp减去8,意思为给square分配栈空间,只用2个栈空间完成计算 str r0, [sp, #4] @第一个参数入栈 str r1, [sp] @第二个参数入栈 ldr r1, [sp, #4] @取出第一个参数给r1 ldr r2, [sp] @取出第二个参数给r2 mul r0, r1, r2 @执行a*b给R0,返回值的工作一直是交给R0的 add sp, sp, #8 @函数执行完了,要释放申请的栈空间 bx lr @子程序返回,等同于mov pc,lr,即跳到调用处 //++++++++++++ square(c -> 汇编)++++++++++++++++++++++++ int fp(int b) { int a = 1; return square(a+b,a+b); } fp(int): push {r11, lr} @r11(fp)/lr入栈,保存调用者main的位置 mov r11, sp @r11用于保存sp值,函数栈开始位置 sub sp, sp, #8 @sp减去8,意思为给fp分配栈空间,只用2个栈空间完成计算 str r0, [sp, #4] @先保存参数值,放在SP+4,此时r0中存放的是参数 mov r0, #1 @r0=1 str r0, [sp] @再把1也保存在SP的位置 ldr r0, [sp] @把SP的值给R0 ldr r1, [sp, #4] @把SP+4的值给R1 add r1, r0, r1 @执行r1=a+b mov r0, r1 @r0=r1,用r0,r1传参 bl square(int, int)@先mov lr, pc 再mov pc square(int, int) mov sp, r11 @函数执行完了,要释放申请的栈空间 pop {r11, lr} @弹出r11和lr,lr是专用标签,弹出就自动复制给lr寄存器 bx lr @子程序返回,等同于mov pc,lr,即跳到调用处 //++++++++++++ main(c -> 汇编)++++++++++++++++++++++++ int main() { int sum = 0; for(int a = 0;a < 100; a++){ sum = sum + fp(a); } return sum; } main: push {r11, lr} @r11(fp)/lr入栈,保存调用者的位置 mov r11, sp @r11用于保存sp值,函数栈开始位置 sub sp, sp, #16 @sp减去8,意思为给main分配栈空间,只用2个栈空间完成计算 mov r0, #0 @初始化r0 str r0, [r11, #-4] @执行sum = 0 str r0, [sp, #8] @sum将始终占用SP+8的位置 str r0, [sp, #4] @a将始终占用SP+4的位置 b .LBB1_1 @跳到循环开始位置 .LBB1_1: @循环开始位置入口 ldr r0, [sp, #4] @取出a的值给r0 cmp r0, #99 @跟99比较 bgt .LBB1_4 @大于99,跳出循环 mov pc .LBB1_4 b .LBB1_2 @继续循环,直接 mov pc .LBB1_2 .LBB1_2: @符合循环条件入口 ldr r0, [sp, #8] @取出sum的值给r0,sp+8用于写SUM的值 str r0, [sp] @先保存SUM的值,SP的位置用于读SUM值 ldr r0, [sp, #4] @r0用于传参,取出A的值给r0作为fp的参数 bl fp(int) @先mov lr, pc再mov pc fp(int) mov r1, r0 @fp的返回值为r0,保存到r1 ldr r0, [sp] @取出SUM的值 add r0, r0, r1 @计算新sum的值,由R0保存 str r0, [sp, #8] @将新sum保存到SP+8的位置 b .LBB1_3 @无条件跳转,直接 mov pc .LBB1_3 .LBB1_3: @完成a++操作入口 ldr r0, [sp, #4] @SP+4中记录是a的值,赋给r0 add r0, r0, #1 @r0增加1 str r0, [sp, #4] @把新的a值放回SP+4里去 b .LBB1_1 @跳转到比较 a < 100 处 .LBB1_4: @循环结束入口 ldr r0, [sp, #8] @最后SUM的结果给R0,返回值的工作一直是交给R0的 mov sp, r11 @函数执行完了,要释放申请的栈空间 pop {r11, lr} @弹出r11和lr,lr是专用标签,弹出就自动复制给lr寄存器 bx lr @子程序返回,跳转到lr处等同于 MOV PC, LR 代码有点长,都加了注释,如果能直接看懂那么恭喜你,鸿蒙内核的6个汇编文件基于也就懂了。这是以下C文件全貌 #include <stdio.h> #include <math.h> int square(int a,int b){ return a*b; } int fp(int b) { int a = 1; return square(a+b,a+b); } int main() { int sum = 0; for(int a = 0;a < 100; a++){ sum = sum + fp(a); } return sum; } 代码很简单谁都能看懂,代码很典型,具有代表性,有循环,有判断,有运算,有多级函数调用。编译后的汇编代码基本和C语言的结构差不太多, 区别是对循环的实现用了四个模块,四个模块也好理解: 一个是开始块(LBB1_1), 一个符合条件的处理块(LBB1_2),一个条件发生变化块(LBB1_3),最后收尾块(LBB1_4). 按块逐一剖析. 先看最短的那个 int square(int a,int b){ return a*b; } //编译成 square(int, int): sub sp, sp, #8 @sp减去8,意思为给square分配栈空间,只用2个栈空间完成计算 str r0, [sp, #4] @第一个参数入栈 str r1, [sp] @第二个参数入栈 ldr r1, [sp, #4] @取出第一个参数给r1 ldr r2, [sp] @取出第二个参数给r2 mul r0, r1, r2 @执行a*b给R0,返回值的工作一直是交给R0的 add sp, sp, #8 @函数执行完了,要释放申请的栈空间 bx lr @子程序返回,等同于mov pc,lr,即跳到调用处 首先上来一句 sub sp, sp, #8 等同于 sp = sp - 8 ,CPU运行需要场地,这个场地就是栈 ,SP是指向栈的指针,表示此时用栈的刻度. 代码和鸿蒙内核用栈方式一样,都采用了递减满栈的方式(FD). 什么是递减满栈? 递减指的是栈底地址高于栈顶地址,栈的生长方向是递减的, 满栈指的是SP指针永远指向栈顶. 每个函数都有自己独立的栈底和栈顶,之间的空间统称栈帧.可以理解为分配了一块 区域给函数运行,sub sp, sp, #8 代表申请2个栈空间,一个栈空间按四个字节算. 用完要不要释放?当然要,add sp, sp, #8 就是释放栈空间. 是一对的,减了又加回去,空间就归还了. ldr r1, [sp, #4] 的意思是取出SP+4这个虚拟地址的值给r1寄存器,而SP的指向并没有改变的,还是在栈顶, 为什么要+呢, +就是往回数, 定位到分配的栈空间上. 一定要理解递减满栈,这是关键! 否则读不懂内核汇编代码. 入参方式 一般都是通过寄存器(r0..r10)传参,fp调用square之前会先将参数给(r0..r10) add r1, r0, r1 @执行r1=a+b mov r0, r1 @r0=r1,用r0,r1传参 bl square(int, int)@先mov lr, pc 再mov pc square(int, int) 到了square中后,先让 r0,r1入栈,目的是保存参数值, 因为 square中要用r0,r1 , str r0, [sp, #4] @先入栈保存第一个参数 str r1, [sp] @再入栈保存第二个参数 ldr r1, [sp, #4] @再取出第一个参数给r1,(a*b)中a值 ldr r2, [sp] @再取出第二个参数给r2,用于计算 (a*b)中b值 是不是感觉这段汇编很傻,直接不保存计算不就完了吗,这个是流程问题,编译器统一先保存参数,至于你想怎么用它不管,也管不了. 另外返回值都是默认统一给r0保存. square中将(a*b)的结果给了r0,回到fp中取出R0对fp来说这就是square的返回值,这是规定. 函数调用 main 和 fp 中都需要调用其他函数,所以都出现了 push {r11, lr} //.... pop {r11, lr} 这哥俩也是成对出现的,这是函数调用的必备装备,作用是保存和恢复调用者的现场,例如 main -> fp, fp要保存main的栈帧范围和指令位置, lr保存的是main函数执行到哪个指令的位置, r11的作用是指向main的栈顶位置,如此fp执行完后return回main的时候,先mov pc,lr, PC寄存器的值一变, 表示执行的代码就变了,又回到了main的指令和栈帧继续未完成的事业. 内存和寄存器数据怎么搬? 数据主要待在两个地方:内存和寄存器. 寄存器<->寄存器 , 内存<->寄存器 , 内存<->内存 搬运指令都不一样. str r1, [sp] @ 寄存器->内存 ldr r1, [sp, #4] @ 内存->寄存器 这又是一对,用于 内存<->寄存器之间,熟知的 mov r0, r1 用于 寄存器<->寄存器 追问三个问题 第一:如果是可变参数怎么办? 100个参数怎么整, 通过寄存器总共就12个,不够传参啊 第二:返回值可以有多个吗? 第三:数据搬运可以不经过CPU吗? 喜欢就请加点源动力吧 鸿蒙内核源码必读篇 < CSDN | OSCHINA | WeHarmony | 源动力 > 鸿蒙内核源码精华篇 < CSDN | OSCHINA | WeHarmony | 源动力 >

优秀的个人博客,低调大师

| 中文注解HarmonyOS源码 | v24.01

鸿蒙内核源码注释仓库 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆, 四大源码仓每日同步更新 < Gitee | Github | CSDN | Coding > 鸿蒙内核源码分析博客 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新 < CSDN | 开源中国 | WeHarmony > 本篇说清楚进程. 读本篇之前建议先读 鸿蒙内核源码分析(总目录) | 精读内核源码 深挖地基工程 < CSDN | 开源中国 | WeHarmony > 调度故事篇,其中有对进程生活场景式的比喻. 官方基本概念 从系统的角度看,进程是资源管理单元。进程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它进程运行。 鸿蒙内核的进程模块可以给用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。这样用户可以将更多的精力投入到业务功能的实现中。 鸿蒙内核中的进程采用抢占式调度机制,支持时间片轮转调度方式和FIFO调度机制。 鸿蒙内核的进程一共有32个优先级(0-31),用户进程可配置的优先级有22个(10-31),最高优先级为10,最低优先级为31。 高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。 每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。 官方概念解读 官方文档最重要的一句话是进程是资源管理单元,注意是管理资源的, 资源是什么? 内存,任务,文件,信号量等等都是资源.故事篇中对进程做了一个形象的比喻(导演),负责节目(任务)的演出,负责协调节目运行时所需的各种资源.让节目能高效顺利的完成. 鸿蒙内核源码分析定位为深挖内核地基,构筑底层网图.就要解剖真身.进程(LosProcessCB)原始真身如下,本篇一一剖析它,看看它的五脏六腑里到底有啥. ProcessCB真身 typedef struct ProcessCB { CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //进程名称 UINT32 processID; /**< process ID = leader thread ID */ //进程ID,由进程池分配,范围[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///这里设计很巧妙.用一个16表示了两层逻辑 数量和状态,点赞! UINT16 priority; /**< process priority */ //进程优先级 UINT16 policy; /**< process policy */ //进程的调度方式,默认抢占式 UINT16 timeSlice; /**< Remaining time slice *///进程时间片,默认2个tick UINT16 consoleID; /**< The console id of task belongs *///任务的控制台id归属 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定为内核还是用户进程 UINT32 parentProcessID; /**< Parent process ID */ //父进程ID UINT32 exitCode; /**< process exit status */ //进程退出状态码 LOS_DL_LIST pendList; /**< Block list to which the process belongs */ //进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上 LOS_DL_LIST childrenList; /**< my children process list */ //孩子进程都挂到这里,形成双循环链表 LOS_DL_LIST exitChildList; /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。 LOS_DL_LIST siblingList; /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程. ProcessGroup *group; /**< Process group to which a process belongs */ //所属进程组 LOS_DL_LIST subordinateGroupList; /**< linkage in my group list */ //进程是组长时,有哪些组员进程 UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */ //哪个线程组是进程的主线程ID UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the process */ //进程的各线程调度位图 LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///进程的线程(任务)列表 LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the priority hash table */ //进程的线程组调度优先级哈希表 volatile UINT32 threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数 UINT32 threadCount; /**< Total number of threads created under this process */ //在此进程下创建的线程总数 LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid #if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///统计各线程被延期或阻塞的时间 #endif UINTPTR sigHandler; /**< signal handler */ //信号处理函数,处理如 SIGSYS 等信号 sigset_t sigShare; /**< signal share bit */ //信号共享位 #if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc #endif LosVmSpace *vmSpace; /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符 #ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器 #endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作 timer_t timerID; /**< iTimer */ #ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //进程的拥有者 UINT32 capability; //安全能力范围 对应 CAP_SETGID #endif #ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap; #endif #ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */ #endif mode_t umask; } LosProcessCB; 结构体还是比较复杂,虽一一都做了注解,但还是不够清晰,没有模块化.这里把它分解成以下六大块逐一分析: 第一大块:和任务(线程)关系 UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */ //哪个线程组是进程的主线程ID UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the process */ //进程的各线程调度位图 LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///进程的线程(任务)列表 LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the priority hash table */ //进程的线程组调度优先级哈希表 volatile UINT32 threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数 UINT32 threadCount; /**< Total number of threads created under this process */ //在此进程下创建的线程总数 LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid 进程和线程的关系是1:N的关系,可以有多个任务但一个任务不能同属于多个进程. 任务就是线程,是CPU的调度单元.任务是什么? 鸿蒙内核源码分析(总目录) | 精读内核源码 深挖地基工程 < CSDN | 开源中国 | WeHarmony > 中的线程概念篇中有详细的介绍,可自行翻看. 任务是作为一种资源被进程管理的,进程为任务提供内存支持,提供文件支持,提供设备支持. 进程怎么管理线程的,进程怎么同步线程的状态? 1.进程加载时会找到main函数创建第一个线程,一般为主线程,其第一条指令就是main的第一条指令,一切从哪里开始. 2.执行线程过程中根据代码创建新的线程,其本质和main函数创建的线程没有区别,统一参与调度. 3.线程和线程的关系可以是独立(detached)的,也可以是联结(join)的.联结指的是一个线程可以操作另一个线程(包括回收资源,被对方干掉). 4.进程的主线程或所有线程运行结束后,进程转为僵尸态,一般只能由所有线程结束后,进程才能自然消亡. 5.进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则该进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存。这里要注意的是进程可以允许多种状态并存! 状态并存很自然的会想到位图管理,系列篇中有对位图详细的介绍. 6.进程内所有的线程均处于阻塞态时,进程在最后一个线程转为阻塞态时,同步进入阻塞态,然后发生进程切换。 7.阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态,若此时发生进程切换,则进程状态由就绪态转为运行态 8.进程内的最后一个就绪态线程处于阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。 9.进程由运行态转为就绪态的情况有以下两种: 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。 若进程的调度策略为SCHED_RR,且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。 第二大块:和其他进程的关系 CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //进程名称 UINT32 processID; /**< process ID = leader thread ID */ //进程ID,由进程池分配,范围[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///这里设计很巧妙.用一个16表示了两层逻辑 数量和状态,点赞! UINT16 priority; /**< process priority */ //进程优先级 UINT16 policy; /**< process policy */ //进程的调度方式,默认抢占式 UINT16 timeSlice; /**< Remaining time slice *///进程时间片,默认2个tick UINT16 consoleID; /**< The console id of task belongs *///任务的控制台id归属 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定为内核还是用户进程 UINT32 parentProcessID; /**< Parent process ID */ //父进程ID UINT32 exitCode; /**< process exit status */ //进程退出状态码 LOS_DL_LIST pendList; /**< Block list to which the process belongs */ //进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上 LOS_DL_LIST childrenList; /**< my children process list */ //孩子进程都挂到这里,形成双循环链表 LOS_DL_LIST exitChildList; /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。 LOS_DL_LIST siblingList; /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程. #if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc #endif 进程是家族式管理的,内核进程和用户进程分别有自己的根祖先,祖先进程在内核初始化时就创建好了,分别是1号(用户进程祖先)和2号(内核进程祖先)进程.进程刚生下来就确定了自己的基因,父亲是谁,兄弟姐妹都有谁,当然你也自己发展自己的孩子进程,最终会形成树状结构,每个进程都能找到自己的位置.进程的管理遵循以下几点原则: 1.进程退出时会主动释放持有的进程资源,但持有的进程pid资源需要父进程通过wait/waitpid或父进程退出时回收. 2.一个子进程的消亡要通知父进程,以便父进程在族谱上抹掉它的痕迹,一些异常情况下的坏孩子进程消亡没有告知父进程的,系统也会检测到而回收其资源. 3.进程创建后,只能操作自己进程空间的资源,无法操作其它进程的资源(共享资源除外). 4.进程间有多种通讯方式,liteipc是进程间基于文件的通讯方式. 5.高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。 第三大块:进程的五种状态 初始化(Init):该进程正在被创建。 就绪(Ready):该进程在就绪列表中,等待CPU调度。 运行(Running):该进程正在运行。 阻塞(Pend):该进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。 僵尸态(Zombies):该进程运行结束,等待父进程回收其控制块资源。 第四大块:和内存的关系 LosVmSpace *vmSpace; /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符 进程与内存有关的就只有LosVmSpace一个,是进程空间,每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离,独立进程空间意味着每个进程都要将自己的虚拟内存和物理内存进行映射.并将映射区保存在自己的进程空间.代码区,数据区,堆栈区,映射区都存放在进程空间中,但内核态进程的空间是共用的,只需一次映射.具体的进入系列篇中 鸿蒙内核源码分析(总目录) | 精读内核源码 深挖地基工程 < CSDN | 开源中国 | WeHarmony > 查看内存篇.详细介绍了虚拟内存,物理内存,线性地址,映射关系,共享内存,分配回收,页面置换的概念和实现. 第五大块:和文件的关系 #ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器 #endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作 进程与文件系统有关的就只有files_struct,可理解为进程的文件管理器,文件也是很复杂的一大块, 后续有系列篇来讲解文件系统的实现. 理解文件系统的主脉络是: 1.一个真实的物理文件(inode),可以同时被多个进程打开,并有进程独立的文件描述符, 进程文件描述符(ProcessFD)后边映射的是系统文件描述符(SystemFD). 2.系统文件描述符(0-stdin,1-stdout,2-stderr)默认被内核占用,任何进程的文件描述符前三个都是(stdin,stdout,stderr),默认已经打开,可以直接往里面读写数据. 3.文件映射跟内存映射一样,每个进程都需要单独对同一个文件进行映射,page_mapping记录了映射关系,而页高速缓存(page cache)提供了文件实际的存放在内存位置. 4.内存<->文件的置换以页为单位(4K),进程并不能对硬盘文件直接操作,必须通过页高速缓存(page cache)完成.其中会涉及到一些经典的概念比如COW(写时拷贝)技术.后续会详细说明. 第六大块:辅助工具 #if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///统计各线程被延期或阻塞的时间 #endif #ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //进程的拥有者 UINT32 capability; //安全能力范围 对应 CAP_SETGID #endif #ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap; #endif #ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */ #endif 其余是一些安全性,统计性的能力. 以上就是进程的五脏六腑,看清楚它鸿蒙内核的影像会清晰很多! 喜欢就请注入源动力吧 各大站点搜 "鸿蒙内核源码分析",快速找到组织.或者更简单的,如图: 鸿蒙内核源码注释仓库 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆, 四大源码仓每日同步更新 < Gitee | Github | CSDN | Coding > 鸿蒙内核源码分析博客 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新 < CSDN | 开源中国 | WeHarmony >

优秀的个人博客,低调大师

| 中文注解HarmonyOS源码 | v24.02

鸿蒙内核源码中文注解 >> 精读内核源码,中文注解分析,深挖地基工程,大脑永久记忆,四大源码仓每日同步更新 本篇说清楚进程 读本篇之前建议先读 鸿蒙内核源码分析(总目录) 调度故事篇,其中有对进程生活场景式的比喻. 官方基本概念 从系统的角度看,进程是资源管理单元。进程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它进程运行。 鸿蒙内核的进程模块可以给用户提供多个进程,实现了进程之间的切换和通信,帮助用户管理业务程序流程。这样用户可以将更多的精力投入到业务功能的实现中。 鸿蒙内核中的进程采用抢占式调度机制,支持时间片轮转调度方式和FIFO调度机制。 鸿蒙内核的进程一共有32个优先级(0-31),用户进程可配置的优先级有22个(10-31),最高优先级为10,最低优先级为31。 高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。 每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离。 官方概念解读 官方文档最重要的一句话是进程是资源管理单元,注意是管理资源的, 资源是什么? 内存,任务,文件,信号量等等都是资源.故事篇中对进程做了一个形象的比喻(导演),负责节目(任务)的演出,负责协调节目运行时所需的各种资源.让节目能高效顺利的完成. 鸿蒙内核源码分析定位为深挖内核地基,构筑底层网图.就要解剖真身.进程(LosProcessCB)原始真身如下,本篇一一剖析它,看看它的五脏六腑里到底有啥. ProcessCB真身 typedef struct ProcessCB { CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //进程名称 UINT32 processID; /**< process ID = leader thread ID */ //进程ID,由进程池分配,范围[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///这里设计很巧妙.用一个16表示了两层逻辑 数量和状态,点赞! UINT16 priority; /**< process priority */ //进程优先级 UINT16 policy; /**< process policy */ //进程的调度方式,默认抢占式 UINT16 timeSlice; /**< Remaining time slice *///进程时间片,默认2个tick UINT16 consoleID; /**< The console id of task belongs *///任务的控制台id归属 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定为内核还是用户进程 UINT32 parentProcessID; /**< Parent process ID */ //父进程ID UINT32 exitCode; /**< process exit status */ //进程退出状态码 LOS_DL_LIST pendList; /**< Block list to which the process belongs */ //进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上 LOS_DL_LIST childrenList; /**< my children process list */ //孩子进程都挂到这里,形成双循环链表 LOS_DL_LIST exitChildList; /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。 LOS_DL_LIST siblingList; /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程. ProcessGroup *group; /**< Process group to which a process belongs */ //所属进程组 LOS_DL_LIST subordinateGroupList; /**< linkage in my group list */ //进程是组长时,有哪些组员进程 UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */ //哪个线程组是进程的主线程ID UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the process */ //进程的各线程调度位图 LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///进程的线程(任务)列表 LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the priority hash table */ //进程的线程组调度优先级哈希表 volatile UINT32 threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数 UINT32 threadCount; /**< Total number of threads created under this process */ //在此进程下创建的线程总数 LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid #if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///统计各线程被延期或阻塞的时间 #endif UINTPTR sigHandler; /**< signal handler */ //信号处理函数,处理如 SIGSYS 等信号 sigset_t sigShare; /**< signal share bit */ //信号共享位 #if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc #endif LosVmSpace *vmSpace; /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符 #ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器 #endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作 timer_t timerID; /**< iTimer */ #ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //进程的拥有者 UINT32 capability; //安全能力范围 对应 CAP_SETGID #endif #ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap; #endif #ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */ #endif mode_t umask; } LosProcessCB; 结构体还是比较复杂,虽一一都做了注解,但还是不够清晰,没有模块化.这里把它分解成以下六大块逐一分析: 第一大块:和任务(线程)关系 UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */ //哪个线程组是进程的主线程ID UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the process */ //进程的各线程调度位图 LOS_DL_LIST threadSiblingList; /**< List of threads under this process *///进程的线程(任务)列表 LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the priority hash table */ //进程的线程组调度优先级哈希表 volatile UINT32 threadNumber; /**< Number of threads alive under this process */ //此进程下的活动线程数 UINT32 threadCount; /**< Total number of threads created under this process */ //在此进程下创建的线程总数 LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid *///进程持有等待链表以支持wait/waitpid 进程和线程的关系是1:N的关系,进程可以有多个任务但一个任务不能同属于多个进程. 任务就是线程,是CPU的调度单元.线程的概念在 鸿蒙内核源码分析(总目录) 中的线程篇中有详细的介绍,可自行翻看. 任务是作为一种资源被进程管理的,进程为任务提供内存支持,提供文件支持,提供设备支持. 进程怎么管理线程的,进程怎么同步线程的状态? 1.进程加载时会找到main函数创建第一个线程,一般为主线程,main函数就是入口函数,一切从哪里开始. 2.执行过程中根据代码(如遇到 new thread )创建新的线程,其本质和main函数创建的线程没有区别,只是入口函数变成了run()[以java举例],统一参与调度. 3.线程和线程的关系可以是独立(detached)的,也可以是联结(join)的.联结指的是一个线程可以操作另一个线程(包括回收资源,被对方干掉). 4.进程的主线程或所有线程运行结束后,进程转为僵尸态,一般只能由所有线程结束后,进程才能自然消亡. 5.进程创建后进入就绪态,发生进程切换时,就绪列表中最高优先级的进程被执行,从而进入运行态。若此时该进程中已无其它线程处于就绪态,则该进程从就绪列表删除,只处于运行态;若此时该进程中还有其它线程处于就绪态,则该进程依旧在就绪队列,此时进程的就绪态和运行态共存。这里要注意的是进程可以允许多种状态并存! 状态并存很自然的会想到位图管理,系列篇中有对位图详细的介绍. 6.进程内所有的线程均处于阻塞态时,进程在最后一个线程转为阻塞态时,同步进入阻塞态,然后发生进程切换。 7.阻塞进程内的任意线程恢复就绪态时,进程被加入到就绪队列,同步转为就绪态,若此时发生进程切换,则进程状态由就绪态转为运行态 8.进程内的最后一个就绪态线程处于阻塞态时,进程从就绪列表中删除,进程由就绪态转为阻塞态。 9.进程由运行态转为就绪态的情况有以下两种: 有更高优先级的进程创建或者恢复后,会发生进程调度,此刻就绪列表中最高优先级进程变为运行态,那么原先运行的进程由运行态变为就绪态。 若进程的调度策略为SCHED_RR(抢占式),且存在同一优先级的另一个进程处于就绪态,则该进程的时间片消耗光之后,该进程由运行态转为就绪态,另一个同优先级的进程由就绪态转为运行态。 第二大块:和其他进程的关系 CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */ //进程名称 UINT32 processID; /**< process ID = leader thread ID */ //进程ID,由进程池分配,范围[0,64] UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently running in the process *///这里设计很巧妙.用一个16表示了两层逻辑 数量和状态,点赞! UINT16 priority; /**< process priority */ //进程优先级 UINT16 policy; /**< process policy */ //进程的调度方式,默认抢占式 UINT16 timeSlice; /**< Remaining time slice *///进程时间片,默认2个tick UINT16 consoleID; /**< The console id of task belongs *///任务的控制台id归属 UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */ //模式指定为内核还是用户进程 UINT32 parentProcessID; /**< Parent process ID */ //父进程ID UINT32 exitCode; /**< process exit status */ //进程退出状态码 LOS_DL_LIST pendList; /**< Block list to which the process belongs */ //进程所属的阻塞列表,如果因拿锁失败,就由此节点挂到等锁链表上 LOS_DL_LIST childrenList; /**< my children process list */ //孩子进程都挂到这里,形成双循环链表 LOS_DL_LIST exitChildList; /**< my exit children process list */ //那些要退出孩子进程挂到这里,白发人送黑发人。 LOS_DL_LIST siblingList; /**< linkage in my parent's children list */ //兄弟进程链表, 56个民族是一家,来自同一个父进程. #if (LOSCFG_KERNEL_LITEIPC == YES) ProcIpcInfo ipcInfo; /**< memory pool for lite ipc */ //用于进程间通讯的虚拟设备文件系统,设备装载点为 /dev/lite_ipc #endif 进程是家族式管理的,内核态进程和用户态进程分别有自己的根祖先,祖先进程在内核初始化时就创建好了,分别是1号(用户进程祖先)和2号(内核进程祖先)进程.进程刚生下来就确定了自己的基因,基因决定了你的权限不同, 父亲是谁,兄弟姐妹都有谁都已经安排好了,跟人一样,没法选择出生. 但进程可以有自己的子子孙孙, 从你这一脉繁衍下来的,这很像人类的传承方式.最终会形成树状结构,每个进程都能找到自己的位置.进程的管理遵循以下几点原则: 1.进程退出时会主动释放持有的进程资源,但持有的进程pid资源需要父进程通过wait/waitpid或父进程退出时回收. 2.一个子进程的消亡要通知父进程,以便父进程在族谱上抹掉它的痕迹,一些异常情况下的坏孩子进程消亡没有告知父进程的,系统也会有定时任务能检测到而回收其资源. 3.进程创建后,只能操作自己进程空间的资源,无法操作其它进程的资源(共享资源除外). 4.进程间有多种通讯方式,事件,信号,消息队列,管道等等, liteipc是进程间基于文件的一种通讯方式,它的特点是传递的信息量可以很大. 5.高优先级的进程可抢占低优先级进程,低优先级进程必须在高优先级进程阻塞或结束后才能得到调度。 第三大块:进程的五种状态 初始化(Init):该进程正在被创建。 就绪(Ready):该进程在就绪列表中,等待CPU调度。 运行(Running):该进程正在运行。 阻塞(Pend):该进程被阻塞挂起。本进程内所有的线程均被阻塞时,进程被阻塞挂起。 僵尸态(Zombies):该进程运行结束,等待父进程回收其控制块资源。 第四大块:和内存的关系 LosVmSpace *vmSpace; /**< VMM space for processes */ //虚拟空间,描述进程虚拟内存的数据结构,linux称为内存描述符 进程与内存有关的就只有LosVmSpace一个成员变量,叫是进程空间,每一个用户态进程均拥有自己独立的进程空间,相互之间不可见,实现进程间隔离,独立进程空间意味着每个进程都要将自己的虚拟内存和物理内存进行映射.并将映射区保存在自己的进程空间.另外进程的代码区,数据区,堆栈区,映射区都存放在自己的空间中,但内核态进程的空间是共用的,只需一次映射.具体的进入 鸿蒙内核源码分析(总目录) 查看内存篇.详细介绍了虚拟内存,物理内存,线性地址,映射关系,共享内存,分配回收,页面置换的概念和实现. 第五大块:和文件的关系 #ifdef LOSCFG_FS_VFS struct files_struct *files; /**< Files held by the process */ //进程所持有的所有文件,注者称之为进程的文件管理器 #endif //每个进程都有属于自己的文件管理器,记录对文件的操作. 注意:一个文件可以被多个进程操作 进程与文件系统有关的就只有files_struct,可理解为进程的文件管理器,文件也是很复杂的一大块, 后续有系列篇来讲解文件系统的实现. 理解文件系统的主脉络是: 1.一个真实的物理文件(inode),可以同时被多个进程打开,并有进程独立的文件描述符, 进程文件描述符(ProcessFD)后边映射的是系统文件描述符(SystemFD). 2.系统文件描述符(0-stdin,1-stdout,2-stderr)默认被内核占用,任何进程的文件描述符前三个都是(stdin,stdout,stderr),默认已经打开,可以直接往里面读写数据. 3.文件映射跟内存映射一样,每个进程都需要单独对同一个文件进行映射,page_mapping记录了映射关系,而页高速缓存(page cache)提供了文件实际内存存放位置. 4.内存<->文件的置换以页为单位(4K),进程并不能对硬盘文件直接操作,必须通过页高速缓存(page cache)完成.其中会涉及到一些经典的概念比如COW(写时拷贝)技术.后续会详细说明. 第六大块:辅助工具 #if (LOSCFG_KERNEL_SMP == YES) UINT32 timerCpu; /**< CPU core number of this task is delayed or pended *///统计各线程被延期或阻塞的时间 #endif #ifdef LOSCFG_SECURITY_CAPABILITY //安全能力 User *user; //进程的拥有者 UINT32 capability; //安全能力范围 对应 CAP_SETGID #endif #ifdef LOSCFG_SECURITY_VID TimerIdMap timerIdMap; #endif #ifdef LOSCFG_DRIVERS_TZDRIVER struct file *execFile; /**< Exec bin of the process */ #endif 其余是一些安全性,统计性的能力. 以上就是进程的五脏六腑,看清楚它鸿蒙内核的影像会清晰很多! 喜欢就请收藏吧 各大站点搜 "鸿蒙内核源码分析" ,快速找到组织. 鸿蒙内核源码分析系列篇 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。