6.4.2 Xenomai xnthread_harden原理

点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

6.4.2 Xenomai xnthread_harden原理

xnthread_harden 函数主要用于把线程从root domain迁移到head domain,以此满足实时任务对低延迟响应的需求。

xnthread_harden 函数最典型的调用场景:
(1)创建xnthread线程后,会执行xnthread_harden切换线程到head domain,参考《6.1 Xenomai进程的创建流程》和《6.2 Xenomai线程的创建流程》。
(2)就是当执行xenomai调用,必须执行xnthread_harden确保线程线切换到head domain,参考《5.4 IPIPE: Xenomai/Linux双核系统调用》。

xnthread_harden中调用的最核心的函数是第1938行的pipeline_leave_inband()函数。

在这里插入图片描述
抽取其中最主要的调用框架,得到如下函数调用堆栈,接下来分3大部分逐步解释其中的玄机。图中用3种颜色来区分3大步骤。

在这里插入图片描述

1. set_current_state(TASK_INTERRUPTIBLE | TASK_HARDENING)

在这里插入图片描述

__ipipe_migrate_head调用 set_current_state 函数,将当前任务task_stuct的state状态更新为 TASK_INTERRUPTIBLE 和 TASK_HARDENING 的组合状态。

  • TASK_INTERRUPTIBLE:这是一个任务状态标志,表示任务处于可中断的睡眠状态。
  • TASK_HARDENING:是Xenomai为task_struct引入的自定义的任务状态标志,用于标记任务正处于从普通状态向实时状态转换的过程。

2. __schedule(false)

在这里插入图片描述

__schedule()是 Linux 内核中核心的调度函数,负责进行任务的切换和调度。它会调用pick_next_task,根据调度算法从运行队列中选择一个合适的任务,执行context_switch将 CPU 控制权交给该任务。

在这里插入图片描述
现在的场景是要把一个任务从Linux切换到Xenomai,为什么__ipipe_migrate_head调用__schedule()来切换Linux的任务呢?
这是有道理的。
当前任务”小沙”占用着CPU,处于执行态。想把它的执行上下文从Linux直接变成Xenoami,非常困难。就好像你不能边开飞机边修飞机吧。
所以,先在root domain,用__schedule函数把当前任务调度出去,重新在Linux的任务队列中拿到一个新的任务“小漏“并执行。这样方便对任务“小沙“继续操作。

具体是怎么操作的呢?接着往下看一下context_switch函数的细节。

在这里插入图片描述
context_switch函数非常复杂,这里就不逐行去解释了,而是抓住最核心两个函数:switch_to和__ipipe_switch_tail。

  • switch_to
    switch_to 是一个关键的上下文切换函数,在 Linux 内核中用于实现任务上下文的切换。prev 是当前正在执行的任务(即将被切换出去的任务),我们还是用“小沙”作为代称。next 是即将要执行的新任务,我们还是用“小漏”作为代称。
    从switch_to函数返回时,已经完成从当前任务 prev 到新任务 next 的上下文切换,包括寄存器状态、栈指针等的切换,使得 CPU 开始执行新任务 next 的代码。这段描述可能有点让人费解,稍微解释一下。
    先想一下,next任务“小漏”曾经是处于执行态的。当“小漏”被调度出去时,也是走到了第2838行的switch_to函数,所以“小漏”的任务上下文中,它就停留在switch_to函数返回的位置。
    然后,一旦当前任务“小沙”被调度出去,把“小漏”调度进来,那么“小漏”还是从switch_to函数返回的位置之后开始向下执行。
    最后,需要注意,任务“小沙”是一体两面的,在Linux有自己的调度实体task_struct,同时在Xenomai有自己的影子线程xnthread。
    switch_to函数只是完成了对task_struct的操作,而对xnthread的操作,就依赖第2841行的Xenomai插入的__ipipe_switch_tail函数。

  • __ipipe_switch_tail
    __ipipe_switch_tail这个函数已经处于任务“小漏”的上下文中了,而任务“小沙”已经处于TASK_INTERRUPTIBLE可中断睡眠状态,此时就时对任务“小沙”进行精准的外科手术。任务“小沙”是一体两面的,在Linux有自己的调度实体task_struct,同时在Xenomai有自己的影子线程xnthread。__ipipe_switch_tail操作的对象必然是xnthread!
    __ipipe_switch_tail具体应该怎么操作?
    它必须调用IPIPE定义的接口函数complete_domain_migration!

3. complete_domain_migration函数

1)t->state &= ~TASK_HARDENING;
将task_stuct的state状态中的TASK_HARDENING标记清除。这个标记是__ipipe_migrate_head调用 set_current_state 函数设置的。这也说明TASK_HARDENING标记表达的就是一个过程状态。

2)ipipe_set_ti_thread_flag(task_thread_info(t), TIP_HEAD);
参考《5.3.2 ipipe_flags之TIP_HEAD》,IPIPE在struct thread_info中新增了ipipe_flags,用于Xenomai/Linux双内核之间进行交互。其中TIP_HEAD代表进程当前运行在Head域。

3)ipipe_migration_hook(t);
在这里插入图片描述

  • 第177行,xnthread_resume(thread, XNRELAX)
    xnthread_resume 函数用于恢复之前通过调用 xnthread_suspend() 而被挂起的线程。此函数通过移除影响目标线程的一个或多个挂起条件来实现这一点。当所有挂起条件都被移除后,线程将进入就绪(READY)状态,并重新具备调度资格。
    传入的第一个参数thread,就是一个xnthread指针:struct xnthread *thread = xnthread_from_task§。它就指向任务“小沙“在Xenomai的影子线程xnthread。
    传入的第二参数XNRELAX,就表示要清除struct xnthread 中的XNRELAX阻塞状态,最终设置XNREADY就绪状态。

  • 第194行,xnsched_run
    xnsched_run会执行调度操作。
    调用xnsched_pick_next(sched)从调度队列中选中一个处于XNREADY的xnthread,假设此时“小沙“xnthread排在了第一,被选中了。
    调用pipeline_switch_to,把选中的“小沙“xnthread调度到CPU上执行,把屁股还没坐热的”小漏“给挤下去了。
    有趣的事情是,xnsched_run最终是复用了Linux的switch_to函数完成任务切换。

xnsched_run
__xnsched_run
pipeline_schedule
___xnsched_run
next = xnsched_pick_next(sched);
	thread = xnsched_rt_pick(sched);//从Multi-level priority queue取出一个thread
	set_thread_running(sched, thread); //把XNREADY清除掉
pipeline_switch_to(prev, next, leaving_inband)
	xnarch_switch_to(prev, next);
		ipipe_switch_to(prev, next)
			switch_to(prev, next, last); //完成切换

小结一下

为了把任务“小沙“从Linux送到Xenomai,xnthread_harden首先在Linux中,把任务”小沙“的tast_struct调度出去,换成了任务”小漏“。
在任务“小漏”屁股还没坐热的时候,把任务“小沙”在Xenomai的影子线程xnthread调到到CPU运行了,把任务“小漏”从CPU上挤下去了。
而且,是在任务“小漏“执行过程中,自己把自己给挤下去了,有点不讲武德哈!

点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值