点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
5.4.3 场景2之运行在Head域Xenomai线程调用Linux系统调用getpid
参考《5.2.2 用户层:用latency演示Xenomai系统调用》,latency 是 Xenomai/Cobalt 实时内核提供的一个工具,用于测量系统的实时性能,特别是上下文切换和中断响应的延迟。它启动后,会新建一个display线程用于打印信息;会新建一个sampling线程用于延迟采样。
通过条件断点,在ipipe_handle_syscall第1200行处,抓到Xenomai实时线程运行在head域时,对Linux系统调用getpid的调用。
- 第一步,ipipe_handle_syscall
- 第二步,__ipipe_notify_syscall
- 第三步,handle_head_syscall
- 第四步,返回KEVENT_PROPAGATE到__ipipe_notify_syscall第1232行
- 第五步,handle_root_syscall函数
- 第六步,返回KEVENT_PROPAGATE(0)到__ipipe_notify_syscall第1232行
- 第七步,KEVENT_PROPAGATE(0)到ipipe_handle_syscall第1200行
- 第八步,返回0到el0_svc_common第110行
接下来对每一步进行分解:
- 第一步,ipipe_handle_syscall
第1199行,条件1(local_flags & _TIP_NOTIFY)成立,因为local_flags即ti->ipipe_flags值为6(_TIP_HEAD | _TIP_NOTIFY)。参考《5.3.2 ipipe_flags之TIP_HEAD》,_TIP_HEAD代表线程当前运行在head domain。参考《5.3.3 ipipe_flags之TIP_NOTIFY》,只要是绑定到xenomai core的进程或线程,一定有TIP_NOTIFY标记!条件2(nr >= nr_syscalls)不成立,因为nr是172,小于Linux自身的系统调用数量nr_syscalls(294)。条件1和条件2是逻辑或的关系,所以第1199行的if判断成立,走到第1200行慢速路径__ipipe_notify_syscall。
第1200行,走到慢速路径__ipipe_notify_syscall
- 第二步,__ipipe_notify_syscall
第1224行,通过__ipipe_current_domain获取当前所在的domain,存入变量caller_domain和this domain。从左上角的locals变量的值能够确认,当前所在domain是head domain。
第1225行,设置变量ipd为ipipe_head_domain即head domain。
第1226行,此处定义了标签next:,在不同的场景下可能会通过goto next跳转过来,形成循环。
第1227行,通过ipd(head domain)获取当前cpu对应的struct ipipe_percpu_domain_data head指针,存入p。
第1228行,参考《5.3.3 ipipe_flags之TIP_NOTIFY》,此处判断必然成立。
第1229行,设置当前cpu的上下文struct ipipe_percpu_data中的curr指向存在p中保存的ipipe_percpu_domain_data head指针。
第1232行,调用ipipe_syscall_hook。在ipipe_syscall_hook中,如果判断当前是secondary domain(即root domain)则调用handle_root_syscall。而因为在__ipipe_notify_syscall的第1229行已经把当前domain设置为head domain,所以ipipe_syscall_hook最终会调用handle_head_syscall。
int ipipe_syscall_hook(struct ipipe_domain *ipd, struct pt_regs *regs)
{
if (unlikely(is_secondary_domain()))
return handle_root_syscall(regs);
return handle_head_syscall(ipd != &xnsched_primary_domain, regs);
}
- 第三步,handle_head_syscall
handle_head_syscall函数比较长,分成两个部分来解释
(1)handle_head_syscall第494~495行
第494行,使用__xn_syscall_p判断系统调用号是否为Xenomai系统调用号。原理参考《5.2.3 内核层:Xenomai系统调用的流程》。当前是Linux系统调用,跳转到495行。
第495行,goto linux_syscall跳转到第647行linux_syscall标签出。
(2)handle_head_syscall第647~679行
第648行,xnsched_root_p 是一个内联函数,用于检查当前线程是否处于 root domain(即 Linux 非实时调度域)。该函数通过调用 xnthread_test_state 来测试当前线程的状态标志位 XNROOT,从而判断线程是否运行在 root domain。当前场景下,task_struct中的ipipe_flags有TIP_HEAD标记,肯定是运行在head domain,此处判断不成立,继续向下执行。
第669行,调用xnthread_relax(1, SIGDEBUG_MIGRATE_SYSCALL); 用于将当前线程从 head domain 切换到 root domain。参数 1表示线程需要立即切换,而不是等待调度机会。参数 SIGDEBUG_MIGRATE_SYSCALL是一个调试信号,用于在调试时跟踪线程的切换行为。
第671行,返回KEVENT_PROPAGATE(0)到第二步中的__ipipe_notify_syscall第1232行。
- 第四步,返回KEVENT_PROPAGATE到__ipipe_notify_syscall第1232行
第1232行,ipipe_syscall_hook返回KEVENT_PROPAGATE(0)。
第1235行,因为在第1232行ipipe_syscall_hook执行过程中,从head domain切换到root domain,所以第1235行条件成立,跳转到第1237行。
第1237行,设置this_domain为当前domain即root domain。
第1242行,根据1237行,判断条件成立,走到第1243行。
第1243行,条件1(ipd != ipipe_root_domain)成立;条件2(ret == 0)成立,因为ipipe_syscall_hook返回KEVENT_PROPAGATE(0)。所以跳转到第1244行。
第1244~1245行,设置ipd为root domain,通过goto next跳转到第1226行。
第1229行,设置当前domain为root domain。
第1232行,进入ipipe_syscall_hook之后,因为当前domain为root domain,所以指向handle_root_syscall函数。
-
第五步,handle_root_syscall函数
第699行,使用__xn_syscall_p判断系统调用号是否为Xenomai系统调用号。原理参考《5.2.3 内核层:Xenomai系统调用的流程》。当前是Linux系统调用,跳转到701行。
第701行,返回KEVENT_PROPAGATE(0)到__ipipe_notify_syscall第1232行。 -
第六步,返回KEVENT_PROPAGATE(0)到__ipipe_notify_syscall第1232行
第1232行,ipipe_syscall_hook返回KEVENT_PROPAGATE(0)。
第1242行,根据1239行,判断条件成立,走到第1243行。
第1243行,条件1(ipd != ipipe_root_domain)不成立;条件2(ret == 0)成立,因为ipipe_syscall_hook返回KEVENT_PROPAGATE(0)。所以不可能走到1245行执行goto next,至此next/go next循环结束。
第1259行,KEVENT_PROPAGATE(0)到ipipe_handle_syscall第1200行。 -
第七步,KEVENT_PROPAGATE(0)到ipipe_handle_syscall第1200行
第1202行,重新读取ti->ipipe_flags,因为已经切换到root domain,所以其中_TIP_HEAD标记已经没有了,此处判断不成立了!
第1204行,因为ret等于KEVENT_PROPAGATE(0),所以跳转到第1208行,返回0到el0_svc_common第110行。 -
第八步,返回0到el0_svc_common第110行
第110行,从ipipe_handle_syscall返回0.
第131行,通过invoke_syscall调用Linux原生系统调用gitpid的系统调用函数__arm64_sys_gitpid! 具体参考《5.1.2 内核层:ARM64 Linux系统调用的流程》。
至此,完成了此场景的分析!
点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!