3.4.1.1 IPIPE基础数据结构

 点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

3.4.1.1 IPIPE基础数据结构

       先上图,按图索骥,一图抵千言。

        前面章节多次提到了Head域(头域)和Root域(根域),它们在IPIPE中抽象成数据结构struct ipipe_domain。一切从根开始,先说Root域(根域)。

        Root域的实例是一个全局变量ipipe_root,它里面的成员ipipe_root.name后续会初始化为“Linux”。为方便访问ipipe_root,为它定义了一个全局指针ipipe_root_domain,后面分析时基本都使用ipipe_root_domain代指Root域。

kernel/ipipe/core.c:
struct ipipe_domain ipipe_root;
EXPORT_SYMBOL_GPL(ipipe_root);

include/linux/ipipe_domain.h:
#define ipipe_root_domain (&ipipe_root)

        Head域的实例化分为两个阶段。第一阶段是IPIPE初始化阶段,定义一个全局指针*ipipe_head_domain指向Root域ipipe_root。第二阶段是Xenomai初始化阶段,调用ipipe_register_head向IPIPE注册名字为“Xenomai”的Head域:xnsched_primary_domain。后面分析时基本都使用ipipe_head_domain代指Head域。

//第一阶段,全局指针指向ipipe_root
kernel/ipipe/core.c:

struct ipipe_domain *ipipe_head_domain = &ipipe_root;
EXPORT_SYMBOL_GPL(ipipe_head_domain);

//第二阶段,Xenomai注册到Head域
kernel/xenomai/pipeline/init.c:
pipeline_init()->ipipe_register_head(&xnsched_primary_domain, "Xenomai");

       IPIPE是支持SMP对称多核CPU的,所以还得为每一个CPU core定义per cpu变量ipipe_percpu,它的数据结构是struct ipipe_percpu_data。这个数据结构里面的成员很多,当前先关注其中的三个变量:root、head、curr!

include/linux/ipipe_domain.h

struct ipipe_percpu_domain_data {
	unsigned long status;	/* <= Must be first in struct. */
	unsigned long irqpend_0map;
#if __IPIPE_IRQMAP_LEVELS >= 3
	unsigned long irqpend_1map[IPIPE_IRQ_1MAPSZ];
#if __IPIPE_IRQMAP_LEVELS >= 4
	unsigned long irqpend_2map[IPIPE_IRQ_2MAPSZ];
#endif
#endif
	unsigned long irqpend_map[IPIPE_IRQ_MAPSZ];
	unsigned long irqheld_map[IPIPE_IRQ_MAPSZ];
	unsigned long irqall[IPIPE_NR_IRQS];
	struct ipipe_domain *domain;
	int coflags;
};

struct ipipe_percpu_data {
	struct ipipe_percpu_domain_data root;
	struct ipipe_percpu_domain_data head;
	struct ipipe_percpu_domain_data *curr;
	struct pt_regs tick_regs;
	int hrtimer_irq;
	struct task_struct *task_hijacked;
	struct task_struct *rqlock_owner;
	struct ipipe_vm_notifier *vm_notifier;
	unsigned long nmi_state;
	struct mm_struct *active_mm;
#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
	int context_check;
	int context_check_saved;
#endif
};

kernel/ipipe/core.c:

DEFINE_PER_CPU(struct ipipe_percpu_data, ipipe_percpu) = {
	.root = {
		.status = IPIPE_STALL_MASK,
		.domain = &ipipe_root,
	},
	.curr = &bootup_context,
	.hrtimer_irq = -1,
#ifdef CONFIG_IPIPE_DEBUG_CONTEXT
	.context_check = 1,
#endif
};
EXPORT_PER_CPU_SYMBOL(ipipe_percpu);

        如何理解root和head两个成员?为了记录Root域ipipe_root_domain和Head域ipipe_head_domain在每个CPU core上留下的身影(即上下文context),struct ipipe_percpu_data为它们各自量身打造了变量root和head,数据结构是struct ipipe_percpu_domain_data。域的运行上下文context有哪些?每个CPU core都要有各自的虚拟中断标志位,就是struct ipipe_percpu_domain_data的成员status。在代码中,ipipe_percpu.root.status被初始化为IPIPE_STALL_MASK。为了方便的找到Root域和Head域,ipipe_percpu.root.domain和ipipe_percpu .head.domain被初始化为ipipe_root_domain和ipipe_head_domain!

        如果理解curr成员?每个CPU core当前处于root和head? struct ipipe_percpu_data又定义了一个curr(current的缩写)指针来指向root或head。

        基础数据结构介绍完了,接下来介绍一下各个数据结构相互访问的API。

        从struct ipipe_percpu_data到struct ipipe_percpu_domain_data,再到struct ipipe_domain,是逐层包含的关系,利用指针可以非常方便地正向地找到每个想要的数据结构或变量,具体如下:

include/linux/ipipe_domain.h:
//获取 ipipe_percpu.root
static inline struct ipipe_percpu_domain_data * ipipe_this_cpu_root_context(void)

//获取 ipipe_percpu.head
static inline struct ipipe_percpu_domain_data * ipipe_this_cpu_head_context(void)

//获取 ipipe_percpu.curr
static inline struct ipipe_percpu_domain_data * __ipipe_get_current_context(void) 
#define __ipipe_current_context __ipipe_get_current_context()
static inline struct ipipe_percpu_domain_data *ipipe_current_context(void)

//获取 ipipe_percpu.curr.domain
static inline struct ipipe_domain *__ipipe_get_current_domain(void)
#define __ipipe_current_domain	__ipipe_get_current_domain()
static inline struct ipipe_domain *ipipe_get_current_domain(void)

        反向思考,假设当前硬塞(传递)过来一个大冤种ipipe_domain指针,它自己都不知道它指向root域还是head域,如何反向找到准确的找到ipipe_percpu.root或是ipipe_percpu.head?

        最简单粗暴的办法,就是判断这个大冤种ipipe_domain的身份,然后正向查询。

如果 ipipe_domain 和 ipipe_root_domain相等
    ipipe_this_cpu_root_context()
否则
    ipipe_this_cpu_head_context()

        IPIPE Patch里面给了一个巧妙的办法。在root域和head域初始化过程中,为其成员context_offset进行赋值:

//在root域初始化过程中赋值
kernel/ipipe/core.c: __ipipe_init_early ()
ipipe_root_domain->context_offset = offsetof(struct ipipe_percpu_data, root)

//在head域初始化过程中赋值
kernel/ipipe/core.c: init_head_stage()
ipipe_head_domain->context_offset = offsetof(struct ipipe_percpu_data, head);

//通过context_offset直接拿到struct ipipe_percpu_domain_data结构指针
static inline struct ipipe_percpu_domain_data *
__context_of(struct ipipe_percpu_data *p, struct ipipe_domain *ipd)
{
	return (void *)p + ipd->context_offset;
}

        IPIPE的基本数据结构介绍告一段落,接下来重点介绍为中断新增的数据结构。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值