Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix priority inversion bug of mutex. #3647

Merged
merged 2 commits into from
Jan 20, 2021
Merged

Conversation

tmmdh
Copy link
Contributor

@tmmdh tmmdh commented Jun 2, 2020

拉取/合并请求描述:(PR description)

[
当存在多个不同优先级的任务同时在申请互斥锁的时候,低优先级的任务在释放了互斥锁后,从该互斥锁的suspend链表上取出一个进程并唤醒执行,此时被唤醒的进程没有进行优先级调整,如果此时系统中存在一个不需要使用该互斥锁的中间优先级的任务,这将造成这个中间优先级的任务比该互斥锁的suspend链表上的高优先级的任务先执行,也就是优先级翻转错误,影响操作系统的实时性;
为了解决该问题,我们在唤醒该互斥锁的suspend链表上的每一个任务时,都应该对被唤醒的任务的优先级进行调整,使之始终与该互斥锁的suspend链表上的所有任务的优先级的最高的优先级保持一致;
该修改项已在qemu-vexpress-a9上完成测试;
]

以下的内容不应该在提交PR时的message修改,修改下述message,PR会被直接关闭。请在提交PR后,浏览器查看PR并对以下检查项逐项check,没问题后逐条在页面上打钩。
The following content must not be changed in submitted PR message. Otherwise, the PR will be closed immediately. After submitted PR, please use web browser to visit PR, and check items one by one, and ticked them if no problem.

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other style
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 本拉取/合并请求代码是高质量的 Code in this PR is of high quality

@tmmdh
Copy link
Contributor Author

tmmdh commented Jun 3, 2020

fix priority inversion bug of mutex.

@BernardXiong BernardXiong self-requested a review June 3, 2020 02:47
@13824125580
Copy link

fix priority inversion bug of mutex.

其它OS是否有类似处理机制?

@tmmdh
Copy link
Contributor Author

tmmdh commented Jun 4, 2020

fix priority inversion bug of mutex.

其它OS是否有类似处理机制?

以下描述基于最新版UCOSIII和LiteOS:

  1. 在这两个RTOS中,当某个进程申请不到互斥锁并将自己挂到互斥锁的suspend链表上时,是按照优先级的从高到底的顺序进行挂载的,即排在suspend链表最前面的进程优先级最高,排在链表末尾的进程的优先级最低,这样在唤醒的时候,从mutex的suspend链表最前面获取到的进程的优先级始终是suspend链表上所有进程中最高的哪一个,此时也就不需要再额外调整优先级了。

  2. rt-thread中RT_IPC_FLAG_PRIO类型的互斥锁处理方式和上面的类似,但是如果在创建互斥锁的时候,互斥锁的类型指定为RT_IPC_FLAG_FIFO时,此时向mutex的suspend链表上添加任务是按照申请mutex的先后顺序,而不是按照优先级从高到低的顺序,此时mutex的suspend链表上的任务的优先级是随机的,无法保证链表最前面的任务的优先级就是最高的,因此,此时需要手动调整被唤醒的任务的优先级,使之与mutex的suspend链表上所有任务中的最高优先级保持一致,这样才能避免唤醒后出现优先级翻转的问题。

UCOSIII参考下面3个接口实现:

  • OSMutexPend
  • OS_Pend
  • OS_PendListInsertPrio

LiteOS参考下面2个接口实现:

  • OsMuxPendOp
  • OsMuxPendFindPos

@tmmdh
Copy link
Contributor Author

tmmdh commented Jun 6, 2020

  • RT_IPC_FLAG_PRIO类型的互斥锁不需要进行优先级调整;
  • 对于RT_IPC_FLAG_FIFO类型的互斥锁,只有当操作系统中存在这样的任务
    a.该任务处于ready或者runing状态;
    b.该任务不使用这个互斥锁;
    c.该任务的优先级处于“要唤醒的任务的优先级”和“这个互斥锁suspend链表上所有任务的最高优先级”之间;

此时才需要对要唤醒的任务进行优先级调整,也就是说只有同时满足下面4个条件时,才会进行优先级调整:

  1. 互斥锁的类型为RT_IPC_FLAG_FIFO;
  2. 等待队列中的最高优先级比系统中的最高优先级要高;
  3. 要恢复的线程的优先级小于系统中的最高优先级;
  4. 要恢复的线程的优先级不等于队列中的最高优先级;

@13824125580
Copy link

  • RT_IPC_FLAG_PRIO类型的互斥锁不需要进行优先级调整;
  • 对于RT_IPC_FLAG_FIFO类型的互斥锁,只有当系统中存在不使用互斥锁的任务,并且该任务的优先级处于“要唤醒的任务的优先级”和“操作系统中已经ready的最高优先级”之间时,才需要对要唤醒的任务进行优先级调整,也就是说只有同时满足下面4个条件时,才会进行优先级调整:
  1. 互斥锁的类型为RT_IPC_FLAG_FIFO;
  2. 等待队列中的最高优先级比系统中的最高优先级要高;
  3. 要恢复的线程的优先级小于系统中的最高优先级;
  4. 要恢复的线程的优先级不等于队列中的最高优先级;

@tmmdh 学习了,ID是我微信,希望能够和你交流。

@tmmdh
Copy link
Contributor Author

tmmdh commented Jun 9, 2020

@BernardXiong 这个问题还有人跟进吗?

@BernardXiong
Copy link
Member

@BernardXiong 这个问题还有人跟进吗?

在看,这里涉及到内核的PR会慢些。另外,不知道是否可以提供测试用的测试用例?

@tmmdh
Copy link
Contributor Author

tmmdh commented Jun 10, 2020

@BernardXiong 这个问题还有人跟进吗?

在看,这里涉及到内核的PR会慢些。另外,不知道是否可以提供测试用的测试用例?

提交的文件中有一个\examples\kernel\mutex_priority.c用例,可以用该用例进行测试,可以在qemu-vexpress-a9中模拟测试的,具体步骤如下:

  1. 编译前需在rtconfig.h中添加"#define HAVE_SYS_SELECT_H"和"#define RT_USING_TC"定义
  2. menuconfig中去掉FINSH_USING_MSH_DEFAULT,默认使用finsh控制台
  3. 编译
  4. 执行下面命令进行模拟,进入finsh控制台后输入"_tc_mutex_priority()"
    qemu-system-arm -M vexpress-a9 -kernel rtthread.bin -serial stdio
  5. 该测试用例中会打印出各个任务的时间戳、原始优先级、当前优先级,通过该测试用例主要观察下面两个现象
  • 任务的原始优先级和当前优先级的值,查看优先级调整操作是否成功;
  • 其中thread22不需要使用互斥锁,观察thread22的运行时刻,查看是否会出现thread22优先于thread20和thread21运行的情况,也就是优先级翻转的情况
  • 通过对rt_mutex_release函数进行修改,取消唤醒前的优先级调整操作,重复上面操作,进行现象对比

@tmmdh
Copy link
Contributor Author

tmmdh commented Aug 1, 2020

@BernardXiong 两个月了,还有进展吗?

@ErnestChen1
Copy link

ErnestChen1 commented Aug 22, 2020

  • RT_IPC_FLAG_PRIO类型的互斥锁不需要进行优先级调整;
  • 对于RT_IPC_FLAG_FIFO类型的互斥锁,只有当操作系统中存在这样的任务
    a.该任务处于ready或者runing状态;
    b.该任务不使用这个互斥锁;
    c.该任务的优先级处于“要唤醒的任务的优先级”和“这个互斥锁suspend链表上所有任务的最高优先级”之间;

此时才需要对要唤醒的任务进行优先级调整,也就是说只有同时满足下面4个条件时,才会进行优先级调整:

  1. 互斥锁的类型为RT_IPC_FLAG_FIFO;
  2. 等待队列中的最高优先级比系统中的最高优先级要高;
  3. 要恢复的线程的优先级小于系统中的最高优先级;
  4. 要恢复的线程的优先级不等于队列中的最高优先级;

引入了新的问题,建议删除第 2 条与第 3 条。本身 mutex 的优先级与当前线程 ready 优先级没有关系,只需要保持 mutex suspend 的最高优先级即可。以下两种情形,按照以上修改均会出现优先级翻转:

1.如果当前系统线程 ready 最高优先级为 idle 线程 ,那么一个线程 take 到 mutex 之后,创建了一个比当前线程更高优先级的线程,但比 mutex suspend 线程中的最高优先级要低,导致这个线程依然无法有效运行,一样是优先级翻转,没有做好保护。

2.优先级为 0 的控制线程 take 到了该 mutex,而 mutex 中还 suspend 测试线程优先级为254,253,252,.....,系统中 ready 比较线程优先级分别为0, 1, 0x7f。

  • 优先级为 0 的控制线程 release mutex,对比系统中 ready 的最高优先级,按照上述条件是不调整优先级
  • 系统中 ready 的比较线程 0,1,0x7f 运行后,才能继续运行 测试线程;第一个 mutex 挂起的线程优先级为 254.

@ErnestChen1
Copy link

我这边没什么问题

@BernardXiong
Copy link
Member

Please fix the conflicting file.

@tmmdh
Copy link
Contributor Author

tmmdh commented Oct 26, 2020

Please fix the conflicting file.
@BernardXiong
the conflicting files have be fixed.

@BernardXiong
Copy link
Member

@Guozhanxin Could you please test it?

@tmmdh
Copy link
Contributor Author

tmmdh commented Jan 19, 2021

@Guozhanxin Could you please test it?

@BernardXiong, @KyleChenjh, @Guozhanxin
这个PR为什么大半年了没有任何进展???Conflicting files还要改几次???

@balanceTWK
Copy link
Member

围观大佬

@Guozhanxin
Copy link
Member

Guozhanxin commented Jan 19, 2021

这个PR看起来确实没什么问题了,之前在忙4.x和3.x的新版本发布,把这份PR给漏了,抱歉了😥

我们的小伙伴也是今天刚处理完新版本的事情:https://github.com/RT-Thread/rt-thread/pull/4248。 明天就帮你测试下,没问题的话,应该就可以合并了。

@KyleChenjh
Copy link

非常抱歉,这个pr很重要,前段时间给忙忘了,现在就帮你测试并给出结果。😥😥

@KyleChenjh
Copy link

@tmmdh 你好,该pr已经测试过,没有问题,只是使用上有个建议,就是在使用 RT_IPC_FLAG_FIFO 时候,由于未进行优先级排列,如果suspend链表上的最后几个线程优先级很高,那么互斥任务在release的时候将自身优先级提升到链表的最高优先级,这就会造成 不需要使用该互斥锁的中间优先级的任务 要一直等待整个链表结束(因为高优先级任务在最后需要等待)才能运行,才能避免优先级反转,这也是这个pr 修改的内容。如果这个等待整个链表的时间的是不能容忍的,那么建议使用 RT_IPC_FLAG_PRIO 的方式进行。

Copy link

@KyleChenjh KyleChenjh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tmmdh 非常抱歉,该pr还需要再解决冲突。

@tmmdh
Copy link
Contributor Author

tmmdh commented Jan 20, 2021

@tmmdh 非常抱歉,该pr还需要再解决冲突。

@KyleChenjh 冲突文件已处理,请关注!

@Guozhanxin Guozhanxin added the +1 Agree +1 label Jan 20, 2021
@BernardXiong BernardXiong merged commit 215c899 into RT-Thread:master Jan 20, 2021
@mysterywolf mysterywolf mentioned this pull request May 17, 2021
9 tasks
BernardXiong added a commit that referenced this pull request Jun 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
+1 Agree +1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants