点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
5.4.4 场景3之运行在root域Xenomai线程调用Xenomai系统调用thread_setname
参考《5.2.2 用户层:用latency演示Xenomai系统调用》,latency 是 Xenomai/Cobalt 实时内核提供的一个工具,用于测量系统的实时性能,特别是上下文切换和中断响应的延迟。它启动后,会新建一个display线程用于打印信息;会新建一个sampling线程用于延迟采样。
通过条件断点,在ipipe_handle_syscall第1200行处,抓到Xenomai实时线程运行在root域时,对Xenomai系统调用thread_setmode的调用。
- 第一步,ipipe_handle_syscall 第二步,__ipipe_notify_syscall
- 第三步,handle_head_syscall
- 第四步,返回KEVENT_PROPAGATE到__ipipe_notify_syscall第1232行
- 第五步,handle_root_syscall函数
- 第六步,返回KEVENT_STOP到__ipipe_notify_syscall第1232行
- 第七步,返回KEVENT_STOP(1)到ipipe_handle_syscall第1200行
- 第八步,返回-1到el0_svc_common第110行
接下来详细解析每一步:
- 第一步,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是0x10000003,大于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第483~第513行
第498行,通过__xn_syscall得到bind在xenomai中的系统调用号3。具体原理参考《5.2.3 内核层:Xenomai系统调用的流程》。
第512行,从Xenomai系统调用表中,找出thread_setmode系统调用的CoBaLt_thread_setmode函数指针。
第513行,从Xenomai系统模式表中,找出thread_setmode系统调用的调用模式。参考《5.2.4 内核层:Xenomai系统调用的定义》,在kernel/xenomai/posix/syscall_entries.h找到thread_setmode系统调用模式为__COBALT_MODE(thread_setmode, primary),代表必须在head domain中运行。
kernel/xenomai/posix/syscall.c:
/* Syscall must run into the Xenomai domain. */
#define __xn_exec_histage 0x2
/* Shadow syscall: caller must be mapped. */
#define __xn_exec_shadow 0x4
/* Shorthand for shadow syscall in Xenomai space. */
#define __xn_exec_primary (__xn_exec_shadow|__xn_exec_histage)
(2)handle_head_syscall第551~第588行
第578行,因为thread_setmode系统调用模式为__COBALT_MODE(thread_setmode, primary),条件成立。
第587行,caller_is_relaxed是true,所有会跳转到第557行。
第588行,返回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函数
(1)第712~713行
第712行,handler指向系统调用函数CoBaLt_thread_setmode.
第713行,sysflags的值为6,因为thread_setmode系统调用模式为__COBALT_MODE(thread_setmode, primary)。
(2)第717~791行
第724行,sysflags的值为6,因为thread_setmode系统调用模式为__COBALT_MODE(thread_setmode, primary)。此处判断成立。
第730行,因为thread_setmode系统调用模式为__COBALT_MODE(thread_setmode, primary),所以需要调用xnthread_harden,将当前任务(root域中的任务)迁移到head域。
第735行,设置switched=1,代表任务发生了域的迁移。
第746行,struct task_struct *p 指向当前进程的task_struct结构体。
第747行,得到传递给系统调用bind的参数,存入args。
第749行,调用系统调用CoBaLt_thread_setmode。
第791行,return KEVENT_STOP(1)到第二步中的__ipipe_notify_syscall第1232行。
- 第六步,返回KEVENT_STOP到__ipipe_notify_syscall第1232行
第1232行,ipipe_syscall_hook返回KEVENT_STOP(1)。
第1242行,根据1239行,判断条件成立,走到第1243行。
第1243行,条件1(ipd != ipipe_root_domain)不成立;条件2(ret == 0)不成立,因为ipipe_syscall_hook返回KEVENT_STOP(1)。所以不可能走到1245行执行goto next,至此next/go next循环结束。
第1259行,返回KEVENT_STOP(1)到ipipe_handle_syscall第1200行。
- 第七步,返回KEVENT_STOP(1)到ipipe_handle_syscall第1200行
第1204行,因为ret等于KEVENT_STOP(1),所以跳转到第1205行,返回-1到el0_svc_common第110行。
- 第八步,返回-1到el0_svc_common第110行
第111行,因为ret等于-1,条件成立,最终在第117行返回,完成系统调用!
第131行,此行完全没有机会也没有必要执行了!
点击查看《Xenomai/IPIPE源代码情景解析》
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!