点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
5.4.5 场景4之运行在root域Xenomai线程调用Linux系统调用read
参考《5.2.2 用户层:用latency演示Xenomai系统调用》,latency 是 Xenomai/Cobalt 实时内核提供的一个工具,用于测量系统的实时性能,特别是上下文切换和中断响应的延迟。它启动后,会新建一个display线程用于打印信息;会新建一个sampling线程用于延迟采样。
通过条件断点,在ipipe_handle_syscall第1200行处,抓到Xenomai实时线程运行在root域时,对Linux系统调用read的调用。
- 第一步,ipipe_handle_syscall

第1199行,条件1(local_flags & _TIP_NOTIFY)成立,因为local_flags即ti->ipipe_flags,值为_TIP_NOTIFY (2)。参考《5.3.3 ipipe_flags之TIP_NOTIFY》,只要是绑定到xenomai core的进程或线程,一定有TIP_NOTIFY标记!条件2(nr >= nr_syscalls)不成立,因为nr是63,小于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。从左上角的local变量的值能够确认,当前所在domain是ipipe_root即root 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。
- 第三步,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标记,肯定是运行在root domain,此处判断成立,跳转到第655行。
第655行,返回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执行过程中,当前domain一直是ipd所指向的head domain(第二步中初始化),所以第1235行条件不成立,跳转到第1239行。
第1239行,设置当前domain为this_domain即root domain(第二步中初始化)。
第1242行,根据1239行,判断条件成立,走到第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行

第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原生系统调用read的系统调用函数__arm64_sys_read! 具体参考《5.1.2 内核层:ARM64 Linux系统调用的流程》。
至此,完成了此场景的分析!
点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
1849

被折叠的 条评论
为什么被折叠?



