Xenomai内核探秘
一直都在使用xenomai,平常或多或少都会看一些xenomai的技术文档,对xenomai也有一个大致了解。最近为了找工作也看了一些操作系统Linux内核相关的信息,下午本来是在看linuxCNC的,但是实在没明白他是如何动态的使用到xenomai实时内核。然后自己就不小心开始看了一眼xenomai的源码。不看不要紧,一看突然醍醐灌顶,好多之前懵懵懂懂的突然就有点通透了。所以决定从今天起把xenomai源码过一遍,顺便探析其实时的实现机理。希望能够坚持下去。
本文包含从0开始的xenomai个人学习见解,也会顺便将之前看到的相关文档抛出,也作为研究生学习生涯的一个小小总结。
基础略有薄弱,如果各位大佬发现什么问题欢迎指正。
xenomai 的启动函数为
xenomai_init(void)
源码中使用如下函数加载到内核的启动过程中。
device_initcall(xenomai_init);
如linux的initcall机制(针对编译进内核的驱动)中描述的情形。xenomai模块是再linux内核启动以后进行加载的,加载过程如下:
start_kernel -> rest_init(); -> kernel_thread(kernel_init, NULL, CLONE_FS); -> kernel_init() -> kernel_init_freeable(); -> do_basic_setup(); -> do_initcalls(); ->do_initcall_level(0); ```` ->do_initcall_level(6);
自此启动xenomai内核;
static int __init xenomai_init(void) { int ret, __maybe_unused cpu; setup_init_state(); if (!realtime_core_enabled()) { printk(XENO_WARNING "disabled on kernel command line\n"); return 0; } #ifdef CONFIG_SMP cpumask_clear(&xnsched_realtime_cpus); for_each_online_cpu(cpu) { if (supported_cpus_arg & (1UL << cpu)) cpumask_set_cpu(cpu, &xnsched_realtime_cpus); } if (cpumask_empty(&xnsched_realtime_cpus)) { printk(XENO_WARNING "disabled via empty real-time CPU mask\n"); set_realtime_core_state(COBALT_STATE_DISABLED); return 0; } cobalt_cpu_affinity = xnsched_realtime_cpus; #endif /* CONFIG_SMP */ xnsched_register_classes(); ret = xnprocfs_init_tree(); if (ret) goto fail; ret = mach_setup(); if (ret) goto cleanup_proc; xnintr_mount(); ret = xnpipe_mount(); if (ret) goto cleanup_mach; ret = xnselect_mount(); if (ret) goto cleanup_pipe; ret = sys_init(); if (ret) goto cleanup_select; ret = mach_late_setup(); if (ret) goto cleanup_sys; ret = rtdm_init(); if (ret) goto cleanup_sys; ret = cobalt_init(); if (ret) goto cleanup_rtdm; rtdm_fd_init(); printk(XENO_INFO "Cobalt v%s %s%s%s%s\n", XENO_VERSION_STRING, boot_debug_notice, boot_lat_trace_notice, boot_evt_trace_notice, boot_state_notice); return 0; cleanup_rtdm: rtdm_cleanup(); cleanup_sys: sys_shutdown(); cleanup_select: xnselect_umount(); cleanup_pipe: xnpipe_umount(); cleanup_mach: mach_cleanup(); cleanup_proc: xnprocfs_cleanup_tree(); fail: set_realtime_core_state(COBALT_STATE_DISABLED); printk(XENO_ERR "init failed, code %d\n", ret); return ret; }
主要包含以下函数
setup_init_state(); set_realtime_core_state(); xnsched_register_classes(); xnprocfs_init_tree(); mach_setup(); xnintr_mount(); xnpipe_mount(); xnselect_mount(); sys_init(); mach_late_setup(); rtdm_init(); cobalt_init(); rtdm_fd_init();
一个一个来
源码如下
static void __init setup_init_state(void) { static char warn_bad_state[] __initdata = XENO_WARNING "invalid init state '%s'\n"; int n; for (n = 0; n < ARRAY_SIZE(init_states); n++) if (strcmp(init_states[n].label, init_state_arg) == 0) { set_realtime_core_state(init_states[n].state); return; } printk(warn_bad_state, init_state_arg); }
这里其他相关参数的说明
static struct { const char *label; enum cobalt_run_states state; } init_states[] __initdata = { { "disabled", COBALT_STATE_DISABLED }, { "stopped", COBALT_STATE_STOPPED }, { "enabled", COBALT_STATE_WARMUP }, }; enum cobalt_run_states { COBALT_STATE_DISABLED, COBALT_STATE_RUNNING, COBALT_STATE_STOPPED, COBALT_STATE_TEARDOWN, COBALT_STATE_WARMUP, };
xenomai对于其状态描述到枚举值类型的映射
static char init_state_arg[16] = "enabled";
默认情况下使能
比较到对应字符传时设置实时核的状态
static inline void set_realtime_core_state(enum cobalt_run_states state) { atomic_set(&cobalt_runstate, state); }
这里的cobalt_runstate 是一个原子变量,其实就是一个int.
static inline void atomic_set(atomic_t *ptr, long v) { ptr->v = v; } typedef struct { int v; } atomic_t; atomic_t cobalt_runstate = ATOMIC_INIT(COBALT_STATE_WARMUP); #define ATOMIC_INIT(__n) { (__n) } //这里的COBALT_STATE_WARMUP就是之前定义的xenomai状态的一种
关于启动状态的设置可以再/etc/default/grub设置
GRUB_CMDLINE_LINUX="isolcpus=0,1 xenomai.supported_cpus=0x03"
官网 Installing_Xenomai_3中有提到
NAME
xenomai.state=
DESCRIPTION
Set the initial state of the Cobalt core at boot up, which may be enabled, stopped or disabled. See the documentation about the corectl(1) utility for a description of these states.
DEFAULT
enabled
corectl 可以再用户级对内核状态进项操作,文档如下corectl - Cobalt core control interface
该工具默认安装在/usr/xenomai/sbin
设置xenomai状态之后就会检查一手,如果没设置成功或者别的问题。就退出,如下
if (!realtime_core_enabled()) { printk(XENO_WARNING "disabled on kernel command line\n"); return 0; }
我之前文章有提到虚拟机安装ubuntu +xenomai3.1补丁
现在的计算机基本都是多核,这个选项默认是要开启的.
#ifdef CONFIG_SMP cpumask_clear(&xnsched_realtime_cpus); for_each_online_cpu(cpu) { if (supported_cpus_arg & (1UL << cpu)) cpumask_set_cpu(cpu, &xnsched_realtime_cpus); } if (cpumask_empty(&xnsched_realtime_cpus)) { printk(XENO_WARNING "disabled via empty real-time CPU mask\n"); set_realtime_core_state(COBALT_STATE_DISABLED); return 0; } cobalt_cpu_affinity = xnsched_realtime_cpus; #endif /* CONFIG_SMP */
cpumask_clear顾名思义掩码清零,定义如下
/** * cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask * @dstp: the cpumask pointer */ static inline void cpumask_clear(struct cpumask *dstp) { bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits); } #define cpumask_bits(maskp) ((maskp)->bits) static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) { if (small_const_nbits(nbits)) *dst = 0UL; else { unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); memset(dst, 0, len); } }
然后设置xenomai支持的cpu掩码
#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) #define for_each_cpu(cpu, mask) \ for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
这里不是很懂为什么cpu只遍历了0,然后设置cpu掩码.
这里也可以设置grub参数传入见官网 [Installing_Xenomai_3]。
cobalt_cpu_affinity = xnsched_realtime_cpus;
然后xenomai的cpu亲和性就会绑定在设置的cpu上面.linux就不会使用这两个核了。
这里可能还有问题,之后再补充.
void xnsched_register_classes(void) { xnsched_register_class(&xnsched_class_idle); #ifdef CONFIG_XENO_OPT_SCHED_WEAK xnsched_register_class(&xnsched_class_weak); #endif #ifdef CONFIG_XENO_OPT_SCHED_TP xnsched_register_class(&xnsched_class_tp); #endif #ifdef CONFIG_XENO_OPT_SCHED_SPORADIC xnsched_register_class(&xnsched_class_sporadic); #endif #ifdef CONFIG_XENO_OPT_SCHED_QUOTA xnsched_register_class(&xnsched_class_quota); #endif xnsched_register_class(&xnsched_class_rt); }
dmesg 显示xenomai 只注册了以下两个
[ 1.629946] [Xenomai] scheduling class idle registered. [ 1.629946] [Xenomai] scheduling class rt registered.