软中断-小结

软中断始终是和中断上半部发生的核绑定在一起的。即中断只发生在0核,那么它对应的下半部也只会在0核上(我感觉应该是待处理的软中断是每个cpu单独记录的,所以其他cpu无法执行)

1、软中断类型是静态定义的,10种

2、软中断回调函数是在本地CPU开中断的情况下执行。因此能够被中断打断,但是软中断无法抢占软中断。因为在irq_exit的时候会判断是否在中断上下文,如果在中断上下文不会去执行软中断。即当一个软中断被中断打断,然后在中断上半部返回时,它不会去执行新的软中断,所以软中断在一个cpu上总是串行执行。

asmlinkage void __do_softirq(void)
{
	...................
	//进入软中断
	local_irq_enable();();
    ............................
	/* 循环处理所有的软中断.总共10个 */
	do {
		if (pending & 1) {
			.................
			h->action(h);
		    ..................
		}
		h++;
		pending >>= 1;
	} while (pending);

	local_irq_disable();
..........................
}

3、 同一类型的软中断可以在多个CPU上并行执行。感觉是raise_softirq并未对CPU限制,也并未对软中断触发的类型做出限制。多个CPU都能触发相同类型的软中断

4、软中断的回调函数不能睡眠,不能使用会导致睡眠的函数。软中断的回调函数在执行的时候,处于软中断上下文,即中断上下文。在硬中断上下文退出时,irq_exit会判断当前是否有待处理的软中断,以及是否处于硬中断上下文和软中断上下文。如果不是才会去处理软中断。虽然这个时候执行软中断,保证了不在软中断上下文。但是后面在处理软中断时,会调用__local_bh_disable(_RET_IP_, SOFTIRQ_OFFSET);将preempt_count的softirq域增加,此时又会进入软中断上下文(local_bh_disable,到local_bh_enab,屏蔽了软中断,这段临界区都属于软中断上下文。。。。不知道为什么,这种情况并未执行软中断,也算软中断上下文

中断运行在中断上下文,没有一个所谓的中断描述符来描述它,它不是操作系统调度的单位。一旦在中断上下文中睡眠,首先无法切换上下文(因为没有中断描述符,当前上下文的状态得不到保存),其次,没有人来唤醒它,因为它不是操作系统的调度单位。从代码上怎么理解呢?是因为在进行进程上下文切换的时候,会出现问题嘛??中断上下文和进程上下文啥区别哦。我感觉还是在中断上下文切换的时候,linux没有定义数据结构去保存中断处理程序时的现场信息。如果在中断上下文进行切换会导致当前中断的信息丢失,无法返回这个现场继续处理中断

5、软中断执行时间点是在硬中断返回前,即退出硬中断上下文时,先检查是否有待处理的软中断,然后在检查是否需要抢占当前进程。软中断上下文总是抢占进程上下文。另外调用raise主动触发也可以zhi

irq_handler-->handle_arch_irq-->gic_handle_irq-->handle_IRQ...这些都是属于中断上半部。即硬中断处理过程,会有irq_enter进行硬中断上下文和irq_exit退出硬中断上下文

在irq_exit时会查看是否需要处理软中断。当这些处理完成之后,才能执行到后面的汇编代码,判断是否开启抢占功能,是否需要抢占当前进程。

软中断上下文执行在进程上下文前。因此前者总是抢占后者

__irq_svc:
.....................
    @中断处理过程
	irq_handler
 
@如果开启了抢占功能,则中断返回时会检查是否可以抢占发生中断时的进程
@检查thread_info->preempt_count是否为0
#ifdef CONFIG_PREEMPT
	get_thread_info tsk
	ldr	r8, [tsk, #TI_PREEMPT]		@ get preempt count
	ldr	r0, [tsk, #TI_FLAGS]		@ get flags
	teq	r8, #0				@ if preempt count != 0
	movne	r0, #0				@ force flags to 0
	tst	r0, #_TIF_NEED_RESCHED
	blne	svc_preempt
#endif
 
	svc_exit r5, irq = 1			@ return from exception
 UNWIND(.fnend		)
ENDPROC(__irq_svc)

tasklet是基于软中断的一种下半部机制

1、tasklet是串行执行的。即同一时刻,同一个tasklet只能在一个CPU上执行(因为从这点来看软中断是比tasklet要快的,同一个软中断同一个时刻可以在不同cpu上执行)。在tasklet_schedule时,会将该tasklet绑定到某个CPU的tasklet_vec链表上。它需要在该CPU执行完其回调函数时,才能和该CPU解绑。才能去其他CPU上执行。

主要是靠SCHED和RUN两个状态构成了串行。tasklet_schedule时,会将taskletA的状态设置为SCHED,如果设置成功,则会被加到本CP的tasklet_vec(反之失败,则表明已经被加入了其他CPU)。在软中断触发,处理tasklet时,又会尝试将taskletA设置为RUN状态(失败则说明已经有CPU在处理该tasklet回调函数)。

static inline void tasklet_schedule(struct tasklet_struct *t)
{
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}
static void tasklet_action(struct softirq_action *a)
{
......................
	/*
	遍历整个链表处理tasklet
	处理tasklet链表是在开中断的情况下进行的
	*/
	while (list) {
................
		/*
		设置tasklet状态为RUN.如果本身已经被RUN(说明该tasklet被其他CPU执行了),则返回false
		本轮不执行该tasklet,这样保证了同一个tasklet只能在同一个CPU上运行
		*/
		if (tasklet_trylock(t)) {
			if (!atomic_read(&t->count)) {/* count = 0,才表示激活状态*/
				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))//清除SCHED标志
					BUG();
				t->func(t->data);
				tasklet_unlock(t);//清除RUN标志
				continue;
			}
			tasklet_unlock(t);
		}
........................
	}
}

中断上下文包含硬中断上下文(hardirq context)和软中断上下文(softirq context)。硬件中断上下文表示硬件中断处理过程。

软中断上下文包含三个部分。

情形1、下半部执行的软中断包括tasklet。irq_exit-->invoke_softirq

情形2、ksoftirqd内核线程执行软中断。eg 系统使能了强制中断线程化。或者是软中断执行时机过长,早do_softirq中唤醒了内核线程ksoftirqd(wakeup_softirqd)

static inline void invoke_softirq(void)
{
	if (!force_irqthreads) {//是否强制中断线程化
............................
	} else {
		wakeup_softirqd();
	}
}
asmlinkage void __do_softirq(void)
{
.......................
    if (pending) {
		/*
		当执行软中断的过程中再次触发软中断。重新执行软中断的条件
		1、软中断处理时间没有超过2ms
		2、当前进程没有调度需求
		3、循环处理的次数不能超过max_restart(10)次
		*/
		if (time_before(jiffies, end) && !need_resched() &&
		    --max_restart)
			goto restart;

		wakeup_softirqd();
	}
}

情形3、进程上下文中调用local_bh_enable也会去处理软中断。local_bh_enable-->do_softirq。情形1运行在中断下半部中。情形2和情形3运行与进程上下文中。linux内核使用以下几个宏进行判断这些情况。 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值