提交 cde71b7c 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

注解说透递归锁的实现,鸿蒙为防止死锁发生默认使用了递归锁,OsMuxPendOp是互斥锁模块最重要的几个函数之一

鸿蒙内核源码分析系列 https://blog.csdn.net/kuangyufei https://my.oschina.net/u/3751245
鸿蒙内核源码注释中文版 【 CSDN仓 | Gitee仓 | Github仓 | Coding仓】四大仓库每日同步更新
给鸿蒙内核源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制.
上级 eac5e22d
[鸿蒙内核源码注释中文版 【 CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制,四大码仓每天同步更新.
[鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制,四大码仓每天同步更新.
[鸿蒙源码分析系列篇 【 CSDN](https://blog.csdn.net/kuangyufei)[ | OSCHINA】](https://my.oschina.net/u/3751245) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
---
# **[kernel_liteos_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
每个码农,职业生涯,都应精读一遍内核源码. 鸿蒙内核源码就是很好的精读项目.一旦熟悉内核代码的实现,将迅速拔高对计算机整体理解,从此高屋建瓴看问题.
## **做了些什么呢**
**[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)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成,正持续加注完善中...
* ### **为何想给鸿蒙源码加上中文注释**
......@@ -29,17 +31,18 @@
鸿蒙是面向未来设计的系统,高瞻远瞩,格局远大,设计精良, 知识点巨多, 把研究过程心得写成鸿蒙源码分析系列篇,如此 源码中文注释+系列篇文章 将加速理解鸿蒙内核实现过程.
系列篇文章 进入 >> [鸿蒙系统源码分析(总目录) 【CSDN](https://blog.csdn.net/kuangyufei) | [OSCHINA】](https://my.oschina.net/u/3751245)查看,感谢CSDN和OSCHINA对博客的推荐支持.
系列篇文章 进入 >> [鸿蒙系统源码分析(总目录) 【CSDN](https://blog.csdn.net/kuangyufei) | [OSCHINA】](https://my.oschina.net/u/3751245)查看,两大站点持续更新....感谢CSDN和OSCHINA对博客的推荐支持.
注释中文版 进入 >> [鸿蒙内核源码注释中文版 【 CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读
注释中文版 进入>> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读,四大仓库每日同步更新....
* ### **加注释方式是怎样的?**
因鸿蒙内核6W+代码量,本身只有很少的注释, 中文注解以不对原有代码侵入为前提,源码所有英文部分都是原有鸿蒙注释,所有中文部分都是笔者的注释,尽量不去增加代码的行数,不破坏文件的结构,注释多类似以下的方式,如图:
因鸿蒙内核6W+代码量,本身只有很少的注释, 中文注解以不对原有代码侵入为前提,源码所有英文部分都是原有鸿蒙注释,所有中文部分都是笔者的注释,尽量不去增加代码的行数,不破坏文件的结构,注释多类似以下的方式,笔者试图把每个知识点当场讲透彻.如图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201022075449282.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020102821375267.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
另外用字符画了一些图方便理解,直接嵌入到头文件中,比如虚拟内存的全景图,因没有这些图是很难理解内存是如何管理的,后续还会陆续加入更多的图方便理解.
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201028154344813.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2t1YW5neXVmZWk=,size_16,color_FFFFFF,t_70#pic_center)
......@@ -62,6 +65,6 @@
系列篇文章 进入 >> [鸿蒙系统源码分析(总目录) 【CSDN](https://blog.csdn.net/kuangyufei) | [OSCHINA】](https://my.oschina.net/u/3751245)查看
注释中文版 进入 >> [鸿蒙内核源码注释中文版 【 CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读
注释中文版 进入 >> [鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files)阅读
内容仅代表个人观点,会反复修正,出精品注解,写精品文章,一律原创,转载需注明出处,不修改内容,错漏之处欢迎指正第一时间加以完善。
\ No newline at end of file
内容仅代表个人观点,会反复修正,出精品注解,写精品文章,一律原创,转载需注明出处,不修改内容,错漏之处欢迎指正笔者第一时间加以完善。
\ No newline at end of file
......@@ -305,7 +305,7 @@ typedef struct {
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function */
VOID *joinRetval; /**< pthread adaption */
VOID *taskSem; /**< Task-held semaphore */
VOID *taskMux; /**< Task-held mutex */
VOID *taskMux; /**< Task-held mutex *///task在等哪把锁
VOID *taskEvent; /**< Task-held event */
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 */
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name */
......
......@@ -309,7 +309,7 @@ STATIC LOS_DL_LIST *OsMuxPendFindPosSub(const LosTaskCB *runTask, const LosMux *
return node;
}
//在等待锁的双向循链表中找一个优先级最高的能释放锁的任务
//在等锁链表中找到一个优先级比当前任务更低的任务
STATIC LOS_DL_LIST *OsMuxPendFindPos(const LosTaskCB *runTask, LosMux *mutex)
{
LosTaskCB *pendedTask1 = NULL;
......@@ -318,21 +318,22 @@ STATIC LOS_DL_LIST *OsMuxPendFindPos(const LosTaskCB *runTask, LosMux *mutex)
if (LOS_ListEmpty(&mutex->muxList)) {//任务列表为空
node = &mutex->muxList;//直接赋给node 返回
} else {
pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&mutex->muxList));//找到第一个持有锁的任务
pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(&mutex->muxList));//找到最后一个持有锁的任务
} else {//muxList上挂的都是task的pendlist节点
pendedTask1 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&mutex->muxList));//找到第一个等锁的任务,
pendedTask2 = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_LAST(&mutex->muxList));//找到最后一个锁的任务
if ((pendedTask1 != NULL) && (pendedTask1->priority > runTask->priority)) {//如果第一个任务优先级低于当前任务 要怎么搞?
node = mutex->muxList.pstNext;//找到了,
node = mutex->muxList.pstNext;//找到了,就是第一个
} else if ((pendedTask2 != NULL) && (pendedTask2->priority <= runTask->priority)) {//如果最后一个任务的优先级高获等于当前任务优先级
node = &mutex->muxList;//找到一个高的了 直接赋给node 返回
} else {
node = &mutex->muxList;//返回自己,这里node就是当前任务的pendlist节点
} else {//当前任务比第一个低,比最后一个高的情况
node = OsMuxPendFindPosSub(runTask, mutex);//找下一级
}
}
return node;
}
//互斥锁的主体函数,由OsMuxlockUnsafe调用
//互斥锁的主体函数,由OsMuxlockUnsafe调用,互斥锁模块最重要的几个函数之一
//最坏情况就是拿锁失败,让出CPU,变成阻塞任务,等别的任务释放锁后排到自己了接着执行.
STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
{
UINT32 ret;
......@@ -343,41 +344,41 @@ STATIC UINT32 OsMuxPendOp(LosTaskCB *runTask, LosMux *mutex, UINT32 timeout)
/* This is for mutex macro initialization. */
mutex->muxCount = 0;//锁计数器清0
mutex->owner = NULL;//锁没有归属任务
LOS_ListInit(&mutex->muxList);//初始化mux链表
LOS_ListInit(&mutex->muxList);//初始化mux链表[]
}
if (mutex->muxCount == 0) {//无task用锁时
if (mutex->muxCount == 0) {//无task用锁时,肯定能拿到锁了.在里面返回
mutex->muxCount++; //互斥锁计数器加1
mutex->owner = (VOID *)runTask; //当前任务拿到锁
LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);//持有锁的任务改变了,节点加入了task的锁链表
LOS_ListTailInsert(&runTask->lockList, &mutex->holdList);//持有锁的任务改变了,节点挂到当前task的锁链表
if ((runTask->priority > mutex->attr.prioceiling) && (mutex->attr.protocol == LOS_MUX_PRIO_PROTECT)) {//看保护协议的做法是怎样的?
LOS_BitmapSet(&runTask->priBitMap, runTask->priority);//1.priBitMap是记录任务优先级变化的位图,这里把任务当前的优先级记录在priBitMap
OsTaskPriModify(runTask, mutex->attr.prioceiling);//2.把高优先级的mutex->attr.prioceiling设为当前任务的优先级.
}//注意任务优先级有32个, 是0最高,31最低!!!这里等于提高了任务的优先级,目的是让其在下次调度中提高选中的概率,从而快速的释放锁.您明白了吗? :|)
}//注意任务优先级有32个, 是0最高,31最低!!!这里等于提高了任务的优先级,目的是让其在下次调度中继续提高被选中的概率,从而快速的释放锁.您明白了吗? :|)
return LOS_OK;
}
if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//LOS_MUX_RECURSIVE类型 是需要计数的
mutex->muxCount++; //互斥锁计数器加1
//递归锁muxCount>0 如果是递归锁就要处理两种情况 1.runtask持有锁 2.锁被别的任务拿走了
if (((LosTaskCB *)mutex->owner == runTask) && (mutex->attr.type == LOS_MUX_RECURSIVE)) {//第一种情况 runtask是锁持有方
mutex->muxCount++; //递归锁计数器加1,递归锁的目的是防止死锁,鸿蒙默认用的就是递归锁(LOS_MUX_DEFAULT = LOS_MUX_RECURSIVE)
return LOS_OK; //成功退出
}
if (!timeout) {//参数timeout表示拿锁等待时间
return LOS_EINVAL;//不等了,没拿到锁就返回不纠结,返回错误.见于LOS_MuxTrylock
//到了这里说明锁在别的任务那里,当前任务只能被阻塞了.
if (!timeout) {//参数timeout表示等待多久再来拿锁
return LOS_EINVAL;//timeout = 0表示不等了,没拿到锁就返回不纠结,返回错误.见于LOS_MuxTrylock
}
if (!OsPreemptableInSched()) {//不能调度的情况(不能调度的原因是因为没有持有调度任务自旋锁)
return LOS_EDEADLK;//返回错误
//自己要被阻塞,只能申请调度,让出CPU core 让别的任务上
if (!OsPreemptableInSched()) {//不能申请调度 (不能调度的原因是因为没有持有调度任务自旋锁)
return LOS_EDEADLK;//返回错误,自旋锁被别的CPU core 持有
}
OsMuxBitmapSet(mutex, runTask, (LosTaskCB *)mutex->owner);//设置bitmap,尽可能的提高锁持有任务的优先级
owner = (LosTaskCB *)mutex->owner; //持有锁任务赋值给临时变量
runTask->taskMux = (VOID *)mutex; //当前任务持有
node = OsMuxPendFindPos(runTask, mutex);//找一个等互斥锁的任务的阻塞链表
owner = (LosTaskCB *)mutex->owner; //记录持有锁的任务
runTask->taskMux = (VOID *)mutex; //记下当前任务在等待这把
node = OsMuxPendFindPos(runTask, mutex);//在都等锁阻塞链表上找一个适当的位置,在OsTaskWait中把自己从这个入口挂上去
ret = OsTaskWait(node, timeout, TRUE);//task陷入等待状态 TRUE代表需要调度
if (ret == LOS_ERRNO_TSK_TIMEOUT) {//超时了
runTask->taskMux = NULL;// taskNux null
if (ret == LOS_ERRNO_TSK_TIMEOUT) {//这行代码虽和OsTaskWait挨在一起,但要过很久才会执行到,因为在OsTaskWait中CPU切换了任务上下文
runTask->taskMux = NULL;// 所以重新回到这里时可能已经超时了
ret = LOS_ETIMEDOUT;//返回超时
}
......@@ -399,34 +400,34 @@ UINT32 OsMuxLockUnsafe(LosMux *mutex, UINT32 timeout)
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
return LOS_EINVAL;
}
//LOS_MUX_ERRORCHECK 时 muxCount是要等于0 ,当前任务持有锁就不能再lock了. 鸿蒙默认用的是 LOS_MUX_RECURSIVE
//LOS_MUX_ERRORCHECK 时 muxCount是要等于0 ,当前任务持有锁就不能再lock了. 鸿蒙默认用的是递归锁LOS_MUX_RECURSIVE
if ((mutex->attr.type == LOS_MUX_ERRORCHECK) && (mutex->muxCount != 0) && (mutex->owner == (VOID *)runTask)) {
return LOS_EDEADLK;
}
return OsMuxPendOp(runTask, mutex, timeout);
}
//尝试加锁,
UINT32 OsMuxTrylockUnsafe(LosMux *mutex, UINT32 timeout)
{
LosTaskCB *runTask = OsCurrTaskGet();
LosTaskCB *runTask = OsCurrTaskGet();//获取当前任务
if (mutex->magic != OS_MUX_MAGIC) {
if (mutex->magic != OS_MUX_MAGIC) {//检查MAGIC有没有被改变
return LOS_EBADF;
}
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {
if (OsCheckMutexAttr(&mutex->attr) != LOS_OK) {//检查互斥锁属性
return LOS_EINVAL;
}
if ((mutex->owner != NULL) && ((LosTaskCB *)mutex->owner != runTask)) {
return LOS_EBUSY;
if ((mutex->owner != NULL) && ((LosTaskCB *)mutex->owner != runTask)) {//已经名锁有主,可惜不是当前任务
return LOS_EBUSY;//返回busy
}
if ((mutex->attr.type != LOS_MUX_RECURSIVE) && (mutex->muxCount != 0)) {
return LOS_EBUSY;
if ((mutex->attr.type != LOS_MUX_RECURSIVE) && (mutex->muxCount != 0)) {//非LOS_MUX_RECURSIVE时 muxCount只能是[0,1]两个值
return LOS_EBUSY;//这里也表示名锁有主了
}
return OsMuxPendOp(runTask, mutex, timeout);
return OsMuxPendOp(runTask, mutex, timeout);//当前任务去拿锁,拿不到就等timeout
}
//拿互斥锁,
LITE_OS_SEC_TEXT UINT32 LOS_MuxLock(LosMux *mutex, UINT32 timeout)
......
......@@ -53,8 +53,8 @@ enum {
};
enum {
LOS_MUX_NORMAL = 0, //不进行deadlock detection(死锁检测)
LOS_MUX_RECURSIVE = 1, //mutex会有一个锁住次数(lock count)的概念。成功一次就++,释放就--
LOS_MUX_NORMAL = 0, //非递归锁 只有[0.1]两个状态,不做任何特殊的错误检,不进行deadlock detection(死锁检测)
LOS_MUX_RECURSIVE = 1, //递归锁 允许同一线程在互斥量解锁前对该互斥量进行多次加锁。递归互斥量维护锁的计数,在解锁次数和加锁次数不相同的情况下,不会释放锁,别的线程就无法加锁此互斥量。
LOS_MUX_ERRORCHECK = 2, //进行错误检查,如果一个线程企图对一个已经锁住的mutex进行relock或对未加锁的unlock,将返回一个错误。
LOS_MUX_DEFAULT = LOS_MUX_RECURSIVE
};
......
git add -A
git commit -m '虚拟内存全景图重画,后续图都用http://asciiflow.com/画
git commit -m '注解说透递归锁的实现,鸿蒙为防止死锁发生默认使用了递归锁,OsMuxPendOp是互斥锁模块最重要的几个函数之一
鸿蒙内核源码分析系列 https://blog.csdn.net/kuangyufei https://my.oschina.net/u/3751245
鸿蒙内核源码注释中文版 【 CSDN仓 | Gitee仓 | Github仓 | Coding仓】四大仓库每日同步更新
给鸿蒙内核源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制.'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册