Xenomai源码解析第一章-xenomai_init(一)

2021/8/7 7:06:22

本文主要是介绍Xenomai源码解析第一章-xenomai_init(一),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Xenomai内核探秘

Xenomai源码解析第一章-xenomai_init(一)

  • 前言
  • 一、xenomai启动前的事情
  • 二、xenomai_init(void)函数
    • setup_init_state()
    • 插曲 smp
    • xnsched_register_classes()


前言

一直都在使用xenomai,平常或多或少都会看一些xenomai的技术文档,对xenomai也有一个大致了解。最近为了找工作也看了一些操作系统Linux内核相关的信息,下午本来是在看linuxCNC的,但是实在没明白他是如何动态的使用到xenomai实时内核。然后自己就不小心开始看了一眼xenomai的源码。不看不要紧,一看突然醍醐灌顶,好多之前懵懵懂懂的突然就有点通透了。所以决定从今天起把xenomai源码过一遍,顺便探析其实时的实现机理。希望能够坚持下去。
本文包含从0开始的xenomai个人学习见解,也会顺便将之前看到的相关文档抛出,也作为研究生学习生涯的一个小小总结。
基础略有薄弱,如果各位大佬发现什么问题欢迎指正。

一、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内核;

二、xenomai_init(void)函数

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();

一个一个来

setup_init_state()

源码如下

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;
	}

插曲 smp

我之前文章有提到虚拟机安装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就不会使用这两个核了。
这里可能还有问题,之后再补充.

xnsched_register_classes()

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.


这篇关于Xenomai源码解析第一章-xenomai_init(一)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程