2.5.4 对CONFIG_PREEMPT的处理

Interrupt Pipeline系列文章大纲-CSDN博客

        2.5 el1_irq

                2.5.1 el1_irq代码框架
                2.5.2 kernel_entry 1与kernel_exit 1
                2.5.3 irq_handler返回值
                2.5.4 对CONFIG_PREEMPT的处理
2.5.4.1 抢占式内核

       没有CONFIG_PREEMPT,就是非抢占式内核,即内核层的代码是不可能抢占的。如果代码运行内核层即运行在EL1异常级别,el1_irq的irq_handler执行完毕后,不会触发调度。

  1. 进程通过系统调用陷入到内核态的时候,进入EL1执行态。如果有更高优先级的进程,只有在系统调用返回用户空间的时候,才可被调度程序调度,由高优先级的进程占用CPU。
  2. 内核进程在运行时,也在EL1执行态,无法被抢占。

        CONFIG_PREEMPT代表在内核层发生中断时,可以进行抢占。对于抢占式内核而言,即便是从中断上下文返回内核空间的进程上下文,只要内核代码不在临界区内,就可以发生抢占,让最高优先级的任务调度执行。

        禁止内核抢占的情况列出如下:

(1)内核执行中断处理例程时不允许内核抢占,中断返回时再执行内核抢占。

(2)当内核执行软中断或tasklet时,禁止内核抢占,软中断返回时再执行内核抢占。

(3)在临界区禁止内核抢占,临界区保护函数通过抢占计数宏控制抢占,计数大于0,表示禁止内核抢占。

        为保证Linux内核在以上情况下不会被抢占,抢占式内核使用了一个变量preempt_ count,称为内核抢占锁。这一变量被设置在进程的PCB结构task_struct中。每当内核要进入以上几种状态时,变量preempt_ count就加1,指示内核不允许抢占。每当内核从以上几种状态退出时,变量preempt_ count就减1,同时进行可抢占的判断与调度。

2.5.4.2 __ipipe_preempt_schedule_irq

       引入了I-pipe后,__ipipe_preempt_schedule_irq取代了preempt_schedule_irq来完成抢占。

#ifdef CONFIG_PREEMPT

el1_preempt:

       mov x24, lr

#ifdef CONFIG_IPIPE

1:    bl    __ipipe_preempt_schedule_irq

#else

1:    bl    preempt_schedule_irq         // irq en/disable is done inside

#endif

       ldr   x0, [tsk, #TSK_TI_FLAGS]      // get new tasks TI_FLAGS

       tbnz x0, #TIF_NEED_RESCHED, 1b      // needs rescheduling?

       ret   x24

#endif

        此时,已经从中断栈切换到了内核栈。此处发生抢占,也是不同进程内核栈直接的切换。但是此处可能会无限抢占。所以需要在__ipipe_preempt_schedule_irq中,1)打开物理中断,让xenomai得以被执行。2)不断处理积压的虚拟中断。

1

void __sched __ipipe_preempt_schedule_irq(void)

2

{

3

struct ipipe_percpu_domain_data *p;

4

unsigned long flags;

5

6

if (WARN_ON_ONCE(!hard_irqs_disabled()))

7

hard_local_irq_disable();

8

9

local_irq_save(flags);

10

hard_local_irq_enable();

11

preempt_schedule_irq(); /* Ok, may reschedule now. */

12

hard_local_irq_disable();

13

14

/*

15

 * Flush any pending interrupt that may have been logged after

16

 * preempt_schedule_irq() stalled the root stage before

17

 * returning to us, and now.

18

*/

19

p = ipipe_this_cpu_root_context();

20

if (unlikely(__ipipe_ipending_p(p))) {

21

trace_hardirqs_on();

22

__clear_bit(IPIPE_STALL_FLAG, &p->status);

23

__ipipe_sync_stage();

24

}

25

26

__ipipe_restore_root_nosync(flags);

27

}

第6~7行,如果硬件中断没有关闭,进行警告,并把硬件中断关闭。注意一旦硬件关闭,那么实时内核也接收不到中断。

第9行,关闭虚拟中断,并将当前虚拟中断状态保存到flags变量。

第10~12行,在打开硬件中断的情况下,调用preempt_schedule_irq,之后再关闭硬件中断。保证了在执行preempt_schedule_irq期间,实时内核可以接收硬件中断。

第14~24行,第9行关闭了虚拟中断,而后在第11行执行preempt_schedule_irq期间,虚拟中断又经历了打开、关闭的过程。只要存在虚拟中断被关闭的情况,那么就有可能出现虚拟中断积压并记录到虚拟中断日志中,需要在此处调用__ipipe_sync_stage()虚拟中断日志的每一条日志进行处理,调用相应虚拟中断处理函数。在__ipipe_sync_stage()执行过程中,硬件中断会被打开,保证实时内核可以接收硬件中断。

第26行,恢复在第9行中保存的虚拟中断状态。

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值